From samuel.thibault at ens-lyon.org  Fri Jan  1 17:40:28 2021
From: samuel.thibault at ens-lyon.org (Samuel Thibault)
Date: Fri, 1 Jan 2021 23:40:28 +0100
Subject: Are AER corrected errors worrying?
Message-ID: <20210101224028.4akud7meibjavvtf@function>

Hello,

Our lab has bought a new Dell Latitude 5410 laptop, I installed debian
bullseye on it with kernel 5.9.0-5-amd64, but it is spitting these
errors now and then (sometimes a dozen per a minute):

Jan  1 23:30:53 begin kernel: [   46.675818] pcieport 0000:00:1d.0: AER: Corrected error received: 0000:02:00.0
Jan  1 23:30:53 begin kernel: [   46.675933] nvme 0000:02:00.0: PCIe Bus Error: severity=Corrected, type=Physical Layer, (Receiver ID)
Jan  1 23:30:53 begin kernel: [   46.676048] nvme 0000:02:00.0:   device [15b7:5006] error status/mask=00000001/0000e000
Jan  1 23:30:53 begin kernel: [   46.676140] nvme 0000:02:00.0:    [ 0] RxErr

Since it's corrected it's not actually an issue, but how worrying is it
to see such errors on new hardware? Documentation/PCI/pcieaer-howto.rst
is not commenting whether we are really supposed to see some of them. I
see forums telling to use pci=noaer to stop the error logging, but is
that really something to do?

Samuel


From Amit.Engel at Dell.com  Sun Jan  3 03:40:35 2021
From: Amit.Engel at Dell.com (Engel, Amit)
Date: Sun, 3 Jan 2021 08:40:35 +0000
Subject: kernel panic in nvmet_tcp when receiving malformed admin command
In-Reply-To: <BL0PR1901MB20671CF789D8C246AF911B4D91330@BL0PR1901MB2067.namprd19.prod.outlook.com>
References: <BL0PR1901MB2067C827A2D826C0FBFE985591320@BL0PR1901MB2067.namprd19.prod.outlook.com>
 <cee26269-c9c3-7ce7-8486-4ed16a632e44@grimberg.me>
 <BL0PR1901MB20671CF789D8C246AF911B4D91330@BL0PR1901MB2067.namprd19.prod.outlook.com>
Message-ID: <DS7PR19MB4439372515F931BA5A1578ABEED30@DS7PR19MB4439.namprd19.prod.outlook.com>

Hi Sagi, is the patch addressing the below issue is already out there? 
-----Original Message-----
From: Anner, Ran <Ran.Anner at dell.com> 
Sent: Wednesday, September 30, 2020 2:28 PM
To: Sagi Grimberg; linux-nvme at lists.infradead.org
Cc: Zinger, Eldad; Grupi, Elad; Engel, Amit
Subject: RE: kernel panic in nvmet_tcp when receiving malformed admin command

Thanks you Sagi.

-----Original Message-----
From: Sagi Grimberg <sagi at grimberg.me> 
Sent: Tuesday, September 29, 2020 11:48 PM
To: Anner, Ran; linux-nvme at lists.infradead.org
Cc: Zinger, Eldad; Grupi, Elad; Engel, Amit
Subject: Re: kernel panic in nvmet_tcp when receiving malformed admin command


[EXTERNAL EMAIL] 


> Hello all.

Hey Ran, thanks for reporting

> 
> We are investigating kernel panic when a malformed admin command with inline write data is sent from host to target using nvmeof tcp.
> Following a code review of nvmet_tcp from latest kernel and adding debug logs along the way I came up with the following flow:
> 
> nvmet_tcp_try_recv_pdu sends an IO with inline data to nvmet_req_init.
> nvmet_req_init send to parse which fails (ex. host sends malformed command).
> nvmet_req_init calls __nvmet_req_complete, and in turn calls queue_response.
> nvmet_tcp_queue_response add the command to queue response list.
> nvmet_req_init return error status and nvmet_tcp_handle_req_failure is called.
> nvmet_tcp_handle_req_failure checks if the command has inline data and will allocate pages and iovs.
> nvmet_tcp_handle_req_failure return and nvmet_tcp_done_recv_pdu returns -EAGAIN.
> nvmet_tcp_try_recv_pdu returns -EAGAIN and in that case nvmet_tcp_try_recv_one returns 0.
> In case nvmet_tcp_try_recv_one returns 0, nvmet_tcp_try_recv breaks from loop and return zero as well.
> In nvmet_tcp_io_work we continue to nvmet_tcp_try_send in case the return value is zero.
> nvmet_tcp_try_send_one will call nvmet_tcp_fetch_cmd which can assign snd_cmd as the failed command.
> nvmet_tcp_need_data_out and nvmet_tcp_need_data_in return false so we call nvmet_setup_response_pdu.
> nvmet_setup_response_pdu set the cmd state to NVMET_TCP_SEND_RESPONSE and return.
> Back to nvmet_tcp_try_send_one, cmd->state == NVMET_TCP_SEND_RESPONSE so nvmet_try_send_response is called.
> After kernel_sendpage we free the cmd iov and sgl.
> Eventually nvmet_tcp_try_recv_data will be called but the iov was already removed and general protection fault is triggered.
> 
> I was wondering if this is a knows issue or if someone else encountered this before.
> It seems to me a fix for this would be to not queue the response before receiving all data in this specific flow.
> Added below snippet of the kernel trace.
> Alternatively if we do not want to delay the response, free the iov after both flows are done, maybe using reference counting to do so.
> I will be glad to hear your thoughts and comments.

This is indeed a bug. We definitely need a refcount here. I recall that this used to work though..

What we probably need to do is to defer the response send until we complete fetching the entire incoming data and then safely free the command.

I'll try to spin a patch soon.

> 
> Thank you,
> Ran.
> 
> [13538.046364] general protection fault: 0000 [#1] SMP NOPTI 
> [13538.051762] CPU: 10 PID: 603 Comm: kworker/10:1H Kdump: loaded 
> Tainted: G?????? ?W? OE???? 4.19.134-coreos-r9999.1600774095-1610 #1 
> [13538.063574] Hardware name: EMC 900-532-002/110-551-910C-01, BIOS 
> 16.35 04/08/2020 [13538.071049] Workqueue: nvmet_tcp_wq 
> nvmet_tcp_io_work [nvmet_tcp] [13538.077142] RIP: 
> 0010:memcpy_erms+0x6/0x10 [13538.081237] Code: 90 90 90 90 eb 1e 0f 1f 
> 00 48 89 f8 48 89 d1 48 c1 e9 03 83 e2 07 f3 48 a5 89 d1 f3 a4 c3 66 
> 0f 1f 44 00 00 48 89 f8 48 89 d1 <f3> a4 c3 0f 1f 80 00 00 00 00 48 89 
> f8 48 83 fa 20 72 7e> [13538.099981] RSP: 0018:ffffc9000781bc70 
> EFLAGS: 00010202 [13538.105199] RAX: 31d247ca1958f63f RBX: 
> 0000000000000510 RCX: 0000000000000510 [13538.112322] RDX: 
> 0000000000000510 RSI: ffff8886445f60ca RDI: 31d247ca1958f63f 
> [13538.119446] RBP: ffff888308c41920 R08: 0000000000000510 R09: 
> ffff88850b96e2bc [13538.126570] R10: ffff88850b96de48 R11: 
> ffff8886445f60ca R12: 0000000000000510 [13538.133693] R13: 
> 0000000000000510 R14: ffff8886445f65da R15: ffff8886902ddd90 
> [13538.140819] FS:? 0000000000000000(0000) GS:ffff8897dfe80000(0000) 
> knlGS:0000000000000000 [13538.148906] CS:? 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [13538.154650] CR2: 00007f547169beb0 CR3: 000000000220a001 CR4: 00000000007606e0 [13538.161772] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [13538.168896] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [13538.176022] PKRU: 55555554 [13538.178726] Call Trace:
> [13538.181171]? _copy_to_iter+0x30e/0x3b0 [13538.184925]? ? 
> wake_up_klogd.part.24+0x30/0x40 [13538.189372]? 
> skb_copy_datagram_iter+0x7b/0x260 [13538.193815]? 
> tcp_recvmsg+0x238/0xc80 [13538.197395]? ? 
> nvmet_tcp_io_work+0x400/0xa80 [nvmet_tcp] [13538.202707]? ? 
> release_sock+0x43/0x90 [13538.206373]? ? tcp_sendpage+0x41/0x50 
> [13538.210038]? inet_recvmsg+0x5b/0xd0 [13538.213522]? 
> nvmet_tcp_io_work+0xea/0xa80 [nvmet_tcp] [13538.218570]? 
> process_one_work+0x206/0x400 [13538.222580]? worker_thread+0x2d/0x3e0 
> [13538.226243]? ? process_one_work+0x400/0x400 [13538.230421]? 
> kthread+0x112/0x130 [13538.233647]? ? kthread_bind+0x20/0x20 
> [13538.237312]? ret_from_fork+0x1f/0x40
> 
> _______________________________________________
> Linux-nvme mailing list
> Linux-nvme at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-nvme
> 

From leonid.ravich at dell.com  Sun Jan  3 13:12:53 2021
From: leonid.ravich at dell.com (leonid.ravich at dell.com)
Date: Sun,  3 Jan 2021 20:12:53 +0200
Subject: [PATCH v2] nvmet-fc: associations list protected by rcu,
 instead of spinlock_irq where possible.
In-Reply-To: <20201224110542.22219-1-leonid.ravich@dell.com>
References: <20201224110542.22219-1-leonid.ravich@dell.com>
Message-ID: <1609697575-103348-1-git-send-email-leonid.ravich@dell.com>

From: Leonid Ravich <Leonid.Ravich at emc.com>

searching assoc_list protected by rcu_read_lock if list not changed inline.
and according to the rcu list rules.

queue array embedded into nvmet_fc_tgt_assoc protected by rcu_read_lock
according to rcu dereference/assign rules.

queue and assoc object freed after grace period by call_rcu.

tgtport lock taken for changing assoc_list.

Reviewed-by: Eldad Zinger <Eldad.Zinger at dell.com>
Reviewed-by: Elad Grupi <Elad.Grupi at dell.com>
Signed-off-by: Leonid Ravich <Leonid.Ravich at emc.com>
---
1) fixed sytle issus 
2) queues array protects by rcu as well

 drivers/nvme/target/fc.c | 81 +++++++++++++++++++++++-------------------------
 1 file changed, 38 insertions(+), 43 deletions(-)

diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c
index cd4e73a..c14c60b 100644
--- a/drivers/nvme/target/fc.c
+++ b/drivers/nvme/target/fc.c
@@ -145,6 +145,7 @@ struct nvmet_fc_tgt_queue {
 	struct list_head		avail_defer_list;
 	struct workqueue_struct		*work_q;
 	struct kref			ref;
+	struct rcu_head			rcu;
 	struct nvmet_fc_fcp_iod		fod[];		/* array of fcp_iods */
 } __aligned(sizeof(unsigned long long));
 
@@ -167,6 +168,7 @@ struct nvmet_fc_tgt_assoc {
 	struct nvmet_fc_tgt_queue	*queues[NVMET_NR_QUEUES + 1];
 	struct kref			ref;
 	struct work_struct		del_work;
+	struct rcu_head			rcu;
 };
 
 
@@ -790,7 +792,6 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
 			u16 qid, u16 sqsize)
 {
 	struct nvmet_fc_tgt_queue *queue;
-	unsigned long flags;
 	int ret;
 
 	if (qid > NVMET_NR_QUEUES)
@@ -829,9 +830,7 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
 		goto out_fail_iodlist;
 
 	WARN_ON(assoc->queues[qid]);
-	spin_lock_irqsave(&assoc->tgtport->lock, flags);
-	assoc->queues[qid] = queue;
-	spin_unlock_irqrestore(&assoc->tgtport->lock, flags);
+	rcu_assign_pointer(assoc->queues[qid], queue);
 
 	return queue;
 
@@ -851,11 +850,8 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
 {
 	struct nvmet_fc_tgt_queue *queue =
 		container_of(ref, struct nvmet_fc_tgt_queue, ref);
-	unsigned long flags;
 
-	spin_lock_irqsave(&queue->assoc->tgtport->lock, flags);
-	queue->assoc->queues[queue->qid] = NULL;
-	spin_unlock_irqrestore(&queue->assoc->tgtport->lock, flags);
+	rcu_assign_pointer(queue->assoc->queues[queue->qid], NULL);
 
 	nvmet_fc_destroy_fcp_iodlist(queue->assoc->tgtport, queue);
 
@@ -863,7 +859,7 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
 
 	destroy_workqueue(queue->work_q);
 
-	kfree(queue);
+	kfree_rcu(queue, rcu);
 }
 
 static void
@@ -965,24 +961,23 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
 	struct nvmet_fc_tgt_queue *queue;
 	u64 association_id = nvmet_fc_getassociationid(connection_id);
 	u16 qid = nvmet_fc_getqueueid(connection_id);
-	unsigned long flags;
 
 	if (qid > NVMET_NR_QUEUES)
 		return NULL;
 
-	spin_lock_irqsave(&tgtport->lock, flags);
-	list_for_each_entry(assoc, &tgtport->assoc_list, a_list) {
+	rcu_read_lock();
+	list_for_each_entry_rcu(assoc, &tgtport->assoc_list, a_list) {
 		if (association_id == assoc->association_id) {
-			queue = assoc->queues[qid];
+			queue = rcu_dereference(assoc->queues[qid]);
 			if (queue &&
 			    (!atomic_read(&queue->connected) ||
 			     !nvmet_fc_tgt_q_get(queue)))
 				queue = NULL;
-			spin_unlock_irqrestore(&tgtport->lock, flags);
+			rcu_read_unlock();
 			return queue;
 		}
 	}
-	spin_unlock_irqrestore(&tgtport->lock, flags);
+	rcu_read_unlock();
 	return NULL;
 }
 
@@ -1137,7 +1132,7 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
 		}
 		if (!needrandom) {
 			assoc->association_id = ran;
-			list_add_tail(&assoc->a_list, &tgtport->assoc_list);
+			list_add_tail_rcu(&assoc->a_list, &tgtport->assoc_list);
 		}
 		spin_unlock_irqrestore(&tgtport->lock, flags);
 	}
@@ -1167,7 +1162,7 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
 
 	nvmet_fc_free_hostport(assoc->hostport);
 	spin_lock_irqsave(&tgtport->lock, flags);
-	list_del(&assoc->a_list);
+	list_del_rcu(&assoc->a_list);
 	oldls = assoc->rcv_disconn;
 	spin_unlock_irqrestore(&tgtport->lock, flags);
 	/* if pending Rcv Disconnect Association LS, send rsp now */
@@ -1177,7 +1172,7 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
 	dev_info(tgtport->dev,
 		"{%d:%d} Association freed\n",
 		tgtport->fc_target_port.port_num, assoc->a_id);
-	kfree(assoc);
+	kfree_rcu(assoc, rcu);
 	nvmet_fc_tgtport_put(tgtport);
 }
 
@@ -1198,7 +1193,6 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
 {
 	struct nvmet_fc_tgtport *tgtport = assoc->tgtport;
 	struct nvmet_fc_tgt_queue *queue;
-	unsigned long flags;
 	int i, terminating;
 
 	terminating = atomic_xchg(&assoc->terminating, 1);
@@ -1207,19 +1201,23 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
 	if (terminating)
 		return;
 
-	spin_lock_irqsave(&tgtport->lock, flags);
+
 	for (i = NVMET_NR_QUEUES; i >= 0; i--) {
-		queue = assoc->queues[i];
-		if (queue) {
-			if (!nvmet_fc_tgt_q_get(queue))
-				continue;
-			spin_unlock_irqrestore(&tgtport->lock, flags);
-			nvmet_fc_delete_target_queue(queue);
-			nvmet_fc_tgt_q_put(queue);
-			spin_lock_irqsave(&tgtport->lock, flags);
+		rcu_read_lock();
+		queue = rcu_dereference(assoc->queues[i]);
+		if (!queue) {
+			rcu_read_unlock();
+			continue;
+		}
+
+		if (!nvmet_fc_tgt_q_get(queue)) {
+			rcu_read_unlock();
+			continue;
 		}
+		rcu_read_unlock();
+		nvmet_fc_delete_target_queue(queue);
+		nvmet_fc_tgt_q_put(queue);
 	}
-	spin_unlock_irqrestore(&tgtport->lock, flags);
 
 	dev_info(tgtport->dev,
 		"{%d:%d} Association deleted\n",
@@ -1234,10 +1232,9 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
 {
 	struct nvmet_fc_tgt_assoc *assoc;
 	struct nvmet_fc_tgt_assoc *ret = NULL;
-	unsigned long flags;
 
-	spin_lock_irqsave(&tgtport->lock, flags);
-	list_for_each_entry(assoc, &tgtport->assoc_list, a_list) {
+	rcu_read_lock();
+	list_for_each_entry_rcu(assoc, &tgtport->assoc_list, a_list) {
 		if (association_id == assoc->association_id) {
 			ret = assoc;
 			if (!nvmet_fc_tgt_a_get(assoc))
@@ -1245,7 +1242,7 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
 			break;
 		}
 	}
-	spin_unlock_irqrestore(&tgtport->lock, flags);
+	rcu_read_unlock();
 
 	return ret;
 }
@@ -1473,19 +1470,17 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
 static void
 __nvmet_fc_free_assocs(struct nvmet_fc_tgtport *tgtport)
 {
-	struct nvmet_fc_tgt_assoc *assoc, *next;
-	unsigned long flags;
+	struct nvmet_fc_tgt_assoc *assoc;
 
-	spin_lock_irqsave(&tgtport->lock, flags);
-	list_for_each_entry_safe(assoc, next,
-				&tgtport->assoc_list, a_list) {
+	rcu_read_lock();
+	list_for_each_entry_rcu(assoc, &tgtport->assoc_list, a_list) {
 		if (!nvmet_fc_tgt_a_get(assoc))
 			continue;
 		if (!schedule_work(&assoc->del_work))
 			/* already deleting - release local reference */
 			nvmet_fc_tgt_a_put(assoc);
 	}
-	spin_unlock_irqrestore(&tgtport->lock, flags);
+	rcu_read_unlock();
 }
 
 /**
@@ -1568,16 +1563,16 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
 			continue;
 		spin_unlock_irqrestore(&nvmet_fc_tgtlock, flags);
 
-		spin_lock_irqsave(&tgtport->lock, flags);
-		list_for_each_entry(assoc, &tgtport->assoc_list, a_list) {
-			queue = assoc->queues[0];
+		rcu_read_lock();
+		list_for_each_entry_rcu(assoc, &tgtport->assoc_list, a_list) {
+			queue = rcu_dereference(assoc->queues[0]);
 			if (queue && queue->nvme_sq.ctrl == ctrl) {
 				if (nvmet_fc_tgt_a_get(assoc))
 					found_ctrl = true;
 				break;
 			}
 		}
-		spin_unlock_irqrestore(&tgtport->lock, flags);
+		rcu_read_unlock();
 
 		nvmet_fc_tgtport_put(tgtport);
 
-- 
1.9.3



From leonid.ravich at dell.com  Sun Jan  3 13:12:54 2021
From: leonid.ravich at dell.com (leonid.ravich at dell.com)
Date: Sun,  3 Jan 2021 20:12:54 +0200
Subject: [PATCH v2] nvmet-fc: associations list protected by rcu,
 instead of spinlock_irq where possible.
In-Reply-To: <1609697575-103348-1-git-send-email-leonid.ravich@dell.com>
References: <20201224110542.22219-1-leonid.ravich@dell.com>
 <1609697575-103348-1-git-send-email-leonid.ravich@dell.com>
Message-ID: <1609697575-103348-2-git-send-email-leonid.ravich@dell.com>

From: Leonid Ravich <Leonid.Ravich at emc.com>

searching assoc_list protected by rcu_read_lock if list not changed inline.
and according to the rcu list rules.

queue array embedded into nvmet_fc_tgt_assoc protected by rcu_read_lock
according to rcu dereference/assign rules.

queue and assoc object freed after grace period by call_rcu.

tgtport lock taken for changing assoc_list.

Reviewed-by: Eldad Zinger <Eldad.Zinger at dell.com>
Reviewed-by: Elad Grupi <Elad.Grupi at dell.com>
Signed-off-by: Leonid Ravich <Leonid.Ravich at emc.com>
---
1) fixed sytle issus 
2) queues array protects by rcu as well

 drivers/nvme/target/fc.c | 81 +++++++++++++++++++++++-------------------------
 1 file changed, 38 insertions(+), 43 deletions(-)

diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c
index cd4e73a..c14c60b 100644
--- a/drivers/nvme/target/fc.c
+++ b/drivers/nvme/target/fc.c
@@ -145,6 +145,7 @@ struct nvmet_fc_tgt_queue {
 	struct list_head		avail_defer_list;
 	struct workqueue_struct		*work_q;
 	struct kref			ref;
+	struct rcu_head			rcu;
 	struct nvmet_fc_fcp_iod		fod[];		/* array of fcp_iods */
 } __aligned(sizeof(unsigned long long));
 
@@ -167,6 +168,7 @@ struct nvmet_fc_tgt_assoc {
 	struct nvmet_fc_tgt_queue	*queues[NVMET_NR_QUEUES + 1];
 	struct kref			ref;
 	struct work_struct		del_work;
+	struct rcu_head			rcu;
 };
 
 
@@ -790,7 +792,6 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
 			u16 qid, u16 sqsize)
 {
 	struct nvmet_fc_tgt_queue *queue;
-	unsigned long flags;
 	int ret;
 
 	if (qid > NVMET_NR_QUEUES)
@@ -829,9 +830,7 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
 		goto out_fail_iodlist;
 
 	WARN_ON(assoc->queues[qid]);
-	spin_lock_irqsave(&assoc->tgtport->lock, flags);
-	assoc->queues[qid] = queue;
-	spin_unlock_irqrestore(&assoc->tgtport->lock, flags);
+	rcu_assign_pointer(assoc->queues[qid], queue);
 
 	return queue;
 
@@ -851,11 +850,8 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
 {
 	struct nvmet_fc_tgt_queue *queue =
 		container_of(ref, struct nvmet_fc_tgt_queue, ref);
-	unsigned long flags;
 
-	spin_lock_irqsave(&queue->assoc->tgtport->lock, flags);
-	queue->assoc->queues[queue->qid] = NULL;
-	spin_unlock_irqrestore(&queue->assoc->tgtport->lock, flags);
+	rcu_assign_pointer(queue->assoc->queues[queue->qid], NULL);
 
 	nvmet_fc_destroy_fcp_iodlist(queue->assoc->tgtport, queue);
 
@@ -863,7 +859,7 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
 
 	destroy_workqueue(queue->work_q);
 
-	kfree(queue);
+	kfree_rcu(queue, rcu);
 }
 
 static void
@@ -965,24 +961,23 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
 	struct nvmet_fc_tgt_queue *queue;
 	u64 association_id = nvmet_fc_getassociationid(connection_id);
 	u16 qid = nvmet_fc_getqueueid(connection_id);
-	unsigned long flags;
 
 	if (qid > NVMET_NR_QUEUES)
 		return NULL;
 
-	spin_lock_irqsave(&tgtport->lock, flags);
-	list_for_each_entry(assoc, &tgtport->assoc_list, a_list) {
+	rcu_read_lock();
+	list_for_each_entry_rcu(assoc, &tgtport->assoc_list, a_list) {
 		if (association_id == assoc->association_id) {
-			queue = assoc->queues[qid];
+			queue = rcu_dereference(assoc->queues[qid]);
 			if (queue &&
 			    (!atomic_read(&queue->connected) ||
 			     !nvmet_fc_tgt_q_get(queue)))
 				queue = NULL;
-			spin_unlock_irqrestore(&tgtport->lock, flags);
+			rcu_read_unlock();
 			return queue;
 		}
 	}
-	spin_unlock_irqrestore(&tgtport->lock, flags);
+	rcu_read_unlock();
 	return NULL;
 }
 
@@ -1137,7 +1132,7 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
 		}
 		if (!needrandom) {
 			assoc->association_id = ran;
-			list_add_tail(&assoc->a_list, &tgtport->assoc_list);
+			list_add_tail_rcu(&assoc->a_list, &tgtport->assoc_list);
 		}
 		spin_unlock_irqrestore(&tgtport->lock, flags);
 	}
@@ -1167,7 +1162,7 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
 
 	nvmet_fc_free_hostport(assoc->hostport);
 	spin_lock_irqsave(&tgtport->lock, flags);
-	list_del(&assoc->a_list);
+	list_del_rcu(&assoc->a_list);
 	oldls = assoc->rcv_disconn;
 	spin_unlock_irqrestore(&tgtport->lock, flags);
 	/* if pending Rcv Disconnect Association LS, send rsp now */
@@ -1177,7 +1172,7 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
 	dev_info(tgtport->dev,
 		"{%d:%d} Association freed\n",
 		tgtport->fc_target_port.port_num, assoc->a_id);
-	kfree(assoc);
+	kfree_rcu(assoc, rcu);
 	nvmet_fc_tgtport_put(tgtport);
 }
 
@@ -1198,7 +1193,6 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
 {
 	struct nvmet_fc_tgtport *tgtport = assoc->tgtport;
 	struct nvmet_fc_tgt_queue *queue;
-	unsigned long flags;
 	int i, terminating;
 
 	terminating = atomic_xchg(&assoc->terminating, 1);
@@ -1207,19 +1201,23 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
 	if (terminating)
 		return;
 
-	spin_lock_irqsave(&tgtport->lock, flags);
+
 	for (i = NVMET_NR_QUEUES; i >= 0; i--) {
-		queue = assoc->queues[i];
-		if (queue) {
-			if (!nvmet_fc_tgt_q_get(queue))
-				continue;
-			spin_unlock_irqrestore(&tgtport->lock, flags);
-			nvmet_fc_delete_target_queue(queue);
-			nvmet_fc_tgt_q_put(queue);
-			spin_lock_irqsave(&tgtport->lock, flags);
+		rcu_read_lock();
+		queue = rcu_dereference(assoc->queues[i]);
+		if (!queue) {
+			rcu_read_unlock();
+			continue;
+		}
+
+		if (!nvmet_fc_tgt_q_get(queue)) {
+			rcu_read_unlock();
+			continue;
 		}
+		rcu_read_unlock();
+		nvmet_fc_delete_target_queue(queue);
+		nvmet_fc_tgt_q_put(queue);
 	}
-	spin_unlock_irqrestore(&tgtport->lock, flags);
 
 	dev_info(tgtport->dev,
 		"{%d:%d} Association deleted\n",
@@ -1234,10 +1232,9 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
 {
 	struct nvmet_fc_tgt_assoc *assoc;
 	struct nvmet_fc_tgt_assoc *ret = NULL;
-	unsigned long flags;
 
-	spin_lock_irqsave(&tgtport->lock, flags);
-	list_for_each_entry(assoc, &tgtport->assoc_list, a_list) {
+	rcu_read_lock();
+	list_for_each_entry_rcu(assoc, &tgtport->assoc_list, a_list) {
 		if (association_id == assoc->association_id) {
 			ret = assoc;
 			if (!nvmet_fc_tgt_a_get(assoc))
@@ -1245,7 +1242,7 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
 			break;
 		}
 	}
-	spin_unlock_irqrestore(&tgtport->lock, flags);
+	rcu_read_unlock();
 
 	return ret;
 }
@@ -1473,19 +1470,17 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
 static void
 __nvmet_fc_free_assocs(struct nvmet_fc_tgtport *tgtport)
 {
-	struct nvmet_fc_tgt_assoc *assoc, *next;
-	unsigned long flags;
+	struct nvmet_fc_tgt_assoc *assoc;
 
-	spin_lock_irqsave(&tgtport->lock, flags);
-	list_for_each_entry_safe(assoc, next,
-				&tgtport->assoc_list, a_list) {
+	rcu_read_lock();
+	list_for_each_entry_rcu(assoc, &tgtport->assoc_list, a_list) {
 		if (!nvmet_fc_tgt_a_get(assoc))
 			continue;
 		if (!schedule_work(&assoc->del_work))
 			/* already deleting - release local reference */
 			nvmet_fc_tgt_a_put(assoc);
 	}
-	spin_unlock_irqrestore(&tgtport->lock, flags);
+	rcu_read_unlock();
 }
 
 /**
@@ -1568,16 +1563,16 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
 			continue;
 		spin_unlock_irqrestore(&nvmet_fc_tgtlock, flags);
 
-		spin_lock_irqsave(&tgtport->lock, flags);
-		list_for_each_entry(assoc, &tgtport->assoc_list, a_list) {
-			queue = assoc->queues[0];
+		rcu_read_lock();
+		list_for_each_entry_rcu(assoc, &tgtport->assoc_list, a_list) {
+			queue = rcu_dereference(assoc->queues[0]);
 			if (queue && queue->nvme_sq.ctrl == ctrl) {
 				if (nvmet_fc_tgt_a_get(assoc))
 					found_ctrl = true;
 				break;
 			}
 		}
-		spin_unlock_irqrestore(&tgtport->lock, flags);
+		rcu_read_unlock();
 
 		nvmet_fc_tgtport_put(tgtport);
 
-- 
1.9.3



From chaitanya.kulkarni at wdc.com  Sun Jan  3 23:51:59 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Sun,  3 Jan 2021 20:51:59 -0800
Subject: [PATCH V2 0/4] nvmet: admin-cmd related cleanups and a fix 
Message-ID: <20210104045203.24472-1-chaitanya.kulkarni@wdc.com>

Hi,

There are three functions where local variable ns is used instead of
using req->ns which leads to duplicate nvmet_put_namespace() calls.
We can just use req->ns and not the local variable to avoid duplicate
calls. First three patches fix that.

The last patch sets the right error status code when namespace is not
found in nvmet_execute_identify_ns().

I've tested this series with nvme blktests, all the testcases are
passing.

-ck

Changes from V1:-

1. Rebase and retest on the latest nvme-5.11.

Chaitanya Kulkarni (4):
  nvmet: remove extra variable in smart log nsid
  nvmet: remove extra variable in identify ns
  nvmet: remove extra variable in id-desclist
  nvmet: set right status on error in id-ns handler

 drivers/nvme/target/admin-cmd.c | 77 +++++++++++++++++----------------
 1 file changed, 39 insertions(+), 38 deletions(-)

Test Result :-

blktests (master) # ./check tests/nvme/
nvme/002 (create many subsystems and test discovery)         [passed]
    runtime  24.027s  ...  24.214s
nvme/003 (test if we're sending keep-alives to a discovery controller) [passed]
    runtime  10.134s  ...  10.134s
nvme/004 (test nvme and nvmet UUID NS descriptors)           [passed]
    runtime  2.463s  ...  2.436s
nvme/005 (reset local loopback target)                       [not run]
    nvme_core module does not have parameter multipath
nvme/006 (create an NVMeOF target with a block device-backed ns) [passed]
    runtime  0.091s  ...  0.093s
nvme/007 (create an NVMeOF target with a file-backed ns)     [passed]
    runtime  0.061s  ...  0.062s
nvme/008 (create an NVMeOF host with a block device-backed ns) [passed]
    runtime  2.446s  ...  2.457s
nvme/009 (create an NVMeOF host with a file-backed ns)       [passed]
    runtime  2.457s  ...  2.427s
nvme/010 (run data verification fio job on NVMeOF block device-backed ns) [passed]
    runtime  19.340s  ...  28.696s
nvme/011 (run data verification fio job on NVMeOF file-backed ns) [passed]
    runtime  225.867s  ...  235.098s
nvme/012 (run mkfs and data verification fio job on NVMeOF block device-backed ns) [passed]
    runtime  42.473s  ...  42.824s
nvme/013 (run mkfs and data verification fio job on NVMeOF file-backed ns) [passed]
    runtime  251.344s  ...  714.369s
nvme/014 (flush a NVMeOF block device-backed ns)             [passed]
    runtime  21.070s  ...  30.622s
nvme/015 (unit test for NVMe flush for file backed ns)       [passed]
    runtime  23.212s  ...  29.880s
nvme/016 (create/delete many NVMeOF block device-backed ns and test discovery) [passed]
    runtime  14.002s  ...  18.465s
nvme/017 (create/delete many file-ns and test discovery)     [passed]
    runtime  13.758s  ...  14.368s
nvme/018 (unit test NVMe-oF out of range access on a file backend) [passed]
    runtime  2.424s  ...  2.458s
nvme/019 (test NVMe DSM Discard command on NVMeOF block-device ns) [passed]
    runtime  2.439s  ...  2.520s
nvme/020 (test NVMe DSM Discard command on NVMeOF file-backed ns) [passed]
    runtime  2.409s  ...  2.586s
nvme/021 (test NVMe list command on NVMeOF file-backed ns)   [passed]
    runtime  2.440s  ...  2.470s
nvme/022 (test NVMe reset command on NVMeOF file-backed ns)  [passed]
    runtime  2.843s  ...  3.091s
nvme/023 (test NVMe smart-log command on NVMeOF block-device ns) [passed]
    runtime  2.439s  ...  2.520s
nvme/024 (test NVMe smart-log command on NVMeOF file-backed ns) [passed]
    runtime  2.419s  ...  2.451s
nvme/025 (test NVMe effects-log command on NVMeOF file-backed ns) [passed]
    runtime  2.417s  ...  2.582s
nvme/026 (test NVMe ns-descs command on NVMeOF file-backed ns) [passed]
    runtime  2.399s  ...  2.546s
nvme/027 (test NVMe ns-rescan command on NVMeOF file-backed ns) [passed]
    runtime  2.419s  ...  2.641s
nvme/028 (test NVMe list-subsys command on NVMeOF file-backed ns) [passed]
    runtime  2.394s  ...  2.575s
nvme/029 (test userspace IO via nvme-cli read/write interface) [passed]
    runtime  2.694s  ...  3.300s
nvme/030 (ensure the discovery generation counter is updated appropriately) [passed]
    runtime  0.327s  ...  0.390s
nvme/031 (test deletion of NVMeOF controllers immediately after setup) [passed]
    runtime  13.381s  ...  15.152s
nvme/038 (test deletion of NVMeOF subsystem without enabling) [passed]
    runtime  0.038s  ...  0.043s

-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Sun Jan  3 23:52:00 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Sun,  3 Jan 2021 20:52:00 -0800
Subject: [PATCH V2 1/4] nvmet: remove extra variable in smart log nsid
In-Reply-To: <20210104045203.24472-1-chaitanya.kulkarni@wdc.com>
References: <20210104045203.24472-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210104045203.24472-2-chaitanya.kulkarni@wdc.com>

We remove the extra local variable struct nvmet_ns in
nvmet_get_smart_log_nsid() since req already has ns member that can be
reused, this also eliminates the explicit call to nvmet_put_namespace()
which is already present in the request completion path.

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/target/admin-cmd.c | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index 8d90235e4fcc..99487dd479a3 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -74,11 +74,11 @@ static void nvmet_execute_get_log_page_error(struct nvmet_req *req)
 static u16 nvmet_get_smart_log_nsid(struct nvmet_req *req,
 		struct nvme_smart_log *slog)
 {
-	struct nvmet_ns *ns;
 	u64 host_reads, host_writes, data_units_read, data_units_written;
 
-	ns = nvmet_find_namespace(req->sq->ctrl, req->cmd->get_log_page.nsid);
-	if (!ns) {
+	req->ns = nvmet_find_namespace(req->sq->ctrl,
+				       req->cmd->get_log_page.nsid);
+	if (!req->ns) {
 		pr_err("Could not find namespace id : %d\n",
 				le32_to_cpu(req->cmd->get_log_page.nsid));
 		req->error_loc = offsetof(struct nvme_rw_command, nsid);
@@ -86,23 +86,21 @@ static u16 nvmet_get_smart_log_nsid(struct nvmet_req *req,
 	}
 
 	/* we don't have the right data for file backed ns */
-	if (!ns->bdev)
+	if (!req->ns->bdev)
 		goto out;
 
-	host_reads = part_stat_read(ns->bdev, ios[READ]);
+	host_reads = part_stat_read(req->ns->bdev, ios[READ]);
 	data_units_read =
-		DIV_ROUND_UP(part_stat_read(ns->bdev, sectors[READ]), 1000);
-	host_writes = part_stat_read(ns->bdev, ios[WRITE]);
+		DIV_ROUND_UP(part_stat_read(req->ns->bdev, sectors[READ]), 1000);
+	host_writes = part_stat_read(req->ns->bdev, ios[WRITE]);
 	data_units_written =
-		DIV_ROUND_UP(part_stat_read(ns->bdev, sectors[WRITE]), 1000);
+		DIV_ROUND_UP(part_stat_read(req->ns->bdev, sectors[WRITE]), 1000);
 
 	put_unaligned_le64(host_reads, &slog->host_reads[0]);
 	put_unaligned_le64(data_units_read, &slog->data_units_read[0]);
 	put_unaligned_le64(host_writes, &slog->host_writes[0]);
 	put_unaligned_le64(data_units_written, &slog->data_units_written[0]);
 out:
-	nvmet_put_namespace(ns);
-
 	return NVME_SC_SUCCESS;
 }
 
-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Sun Jan  3 23:52:01 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Sun,  3 Jan 2021 20:52:01 -0800
Subject: [PATCH V2 2/4] nvmet: remove extra variable in identify ns
In-Reply-To: <20210104045203.24472-1-chaitanya.kulkarni@wdc.com>
References: <20210104045203.24472-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210104045203.24472-3-chaitanya.kulkarni@wdc.com>

We remove the extra local variable struct nvmet_ns in
nvmet_execute_identify_ns() since req already has ns member that can be
reused, this also eliminates the explicit call to nvmet_put_namespace()
which is already present in the request completion path.

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/target/admin-cmd.c | 31 +++++++++++++++----------------
 1 file changed, 15 insertions(+), 16 deletions(-)

diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index 99487dd479a3..eeee2f4a30be 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -467,7 +467,6 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
 static void nvmet_execute_identify_ns(struct nvmet_req *req)
 {
 	struct nvmet_ctrl *ctrl = req->sq->ctrl;
-	struct nvmet_ns *ns;
 	struct nvme_id_ns *id;
 	u16 status = 0;
 
@@ -484,18 +483,19 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req)
 	}
 
 	/* return an all zeroed buffer if we can't find an active namespace */
-	ns = nvmet_find_namespace(ctrl, req->cmd->identify.nsid);
-	if (!ns)
+	req->ns = nvmet_find_namespace(ctrl, req->cmd->identify.nsid);
+	if (!req->ns)
 		goto done;
 
-	nvmet_ns_revalidate(ns);
+	nvmet_ns_revalidate(req->ns);
 
 	/*
 	 * nuse = ncap = nsze isn't always true, but we have no way to find
 	 * that out from the underlying device.
 	 */
-	id->ncap = id->nsze = cpu_to_le64(ns->size >> ns->blksize_shift);
-	switch (req->port->ana_state[ns->anagrpid]) {
+	id->ncap = id->nsze =
+		cpu_to_le64(req->ns->size >> req->ns->blksize_shift);
+	switch (req->port->ana_state[req->ns->anagrpid]) {
 	case NVME_ANA_INACCESSIBLE:
 	case NVME_ANA_PERSISTENT_LOSS:
 		break;
@@ -504,8 +504,8 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req)
 		break;
         }
 
-	if (ns->bdev)
-		nvmet_bdev_set_limits(ns->bdev, id);
+	if (req->ns->bdev)
+		nvmet_bdev_set_limits(req->ns->bdev, id);
 
 	/*
 	 * We just provide a single LBA format that matches what the
@@ -519,25 +519,24 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req)
 	 * controllers, but also with any other user of the block device.
 	 */
 	id->nmic = (1 << 0);
-	id->anagrpid = cpu_to_le32(ns->anagrpid);
+	id->anagrpid = cpu_to_le32(req->ns->anagrpid);
 
-	memcpy(&id->nguid, &ns->nguid, sizeof(id->nguid));
+	memcpy(&id->nguid, &req->ns->nguid, sizeof(id->nguid));
 
-	id->lbaf[0].ds = ns->blksize_shift;
+	id->lbaf[0].ds = req->ns->blksize_shift;
 
-	if (ctrl->pi_support && nvmet_ns_has_pi(ns)) {
+	if (ctrl->pi_support && nvmet_ns_has_pi(req->ns)) {
 		id->dpc = NVME_NS_DPC_PI_FIRST | NVME_NS_DPC_PI_LAST |
 			  NVME_NS_DPC_PI_TYPE1 | NVME_NS_DPC_PI_TYPE2 |
 			  NVME_NS_DPC_PI_TYPE3;
 		id->mc = NVME_MC_EXTENDED_LBA;
-		id->dps = ns->pi_type;
+		id->dps = req->ns->pi_type;
 		id->flbas = NVME_NS_FLBAS_META_EXT;
-		id->lbaf[0].ms = cpu_to_le16(ns->metadata_size);
+		id->lbaf[0].ms = cpu_to_le16(req->ns->metadata_size);
 	}
 
-	if (ns->readonly)
+	if (req->ns->readonly)
 		id->nsattr |= (1 << 0);
-	nvmet_put_namespace(ns);
 done:
 	status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id));
 	kfree(id);
-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Sun Jan  3 23:52:02 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Sun,  3 Jan 2021 20:52:02 -0800
Subject: [PATCH V2 3/4] nvmet: remove extra variable in id-desclist
In-Reply-To: <20210104045203.24472-1-chaitanya.kulkarni@wdc.com>
References: <20210104045203.24472-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210104045203.24472-4-chaitanya.kulkarni@wdc.com>

We remove the extra local variable struct nvmet_ns in
nvmet_execute_identify_desclist() since req already has ns member that
can be reused, this also eliminates the explicit call to
nvmet_put_namespace() which is already present in the request
completion path.

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/target/admin-cmd.c | 20 +++++++++-----------
 1 file changed, 9 insertions(+), 11 deletions(-)

diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index eeee2f4a30be..955ca5a653fb 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -600,37 +600,35 @@ static u16 nvmet_copy_ns_identifier(struct nvmet_req *req, u8 type, u8 len,
 
 static void nvmet_execute_identify_desclist(struct nvmet_req *req)
 {
-	struct nvmet_ns *ns;
 	u16 status = 0;
 	off_t off = 0;
 
-	ns = nvmet_find_namespace(req->sq->ctrl, req->cmd->identify.nsid);
-	if (!ns) {
+	req->ns = nvmet_find_namespace(req->sq->ctrl, req->cmd->identify.nsid);
+	if (!req->ns) {
 		req->error_loc = offsetof(struct nvme_identify, nsid);
 		status = NVME_SC_INVALID_NS | NVME_SC_DNR;
 		goto out;
 	}
 
-	if (memchr_inv(&ns->uuid, 0, sizeof(ns->uuid))) {
+	if (memchr_inv(&req->ns->uuid, 0, sizeof(req->ns->uuid))) {
 		status = nvmet_copy_ns_identifier(req, NVME_NIDT_UUID,
 						  NVME_NIDT_UUID_LEN,
-						  &ns->uuid, &off);
+						  &req->ns->uuid, &off);
 		if (status)
-			goto out_put_ns;
+			goto out;
 	}
-	if (memchr_inv(ns->nguid, 0, sizeof(ns->nguid))) {
+	if (memchr_inv(req->ns->nguid, 0, sizeof(req->ns->nguid))) {
 		status = nvmet_copy_ns_identifier(req, NVME_NIDT_NGUID,
 						  NVME_NIDT_NGUID_LEN,
-						  &ns->nguid, &off);
+						  &req->ns->nguid, &off);
 		if (status)
-			goto out_put_ns;
+			goto out;
 	}
 
 	if (sg_zero_buffer(req->sg, req->sg_cnt, NVME_IDENTIFY_DATA_SIZE - off,
 			off) != NVME_IDENTIFY_DATA_SIZE - off)
 		status = NVME_SC_INTERNAL | NVME_SC_DNR;
-out_put_ns:
-	nvmet_put_namespace(ns);
+
 out:
 	nvmet_req_complete(req, status);
 }
-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Sun Jan  3 23:52:03 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Sun,  3 Jan 2021 20:52:03 -0800
Subject: [PATCH V2 4/4] nvmet: set right status on error in id-ns handler
In-Reply-To: <20210104045203.24472-1-chaitanya.kulkarni@wdc.com>
References: <20210104045203.24472-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210104045203.24472-5-chaitanya.kulkarni@wdc.com>

The function nvmet_execute_identify_ns() does't set the status
if call to nvmet_find_namespace() fails. In that case we set the
status of the request to the value return by the nvmet_copy_sgl().

Set the status to NVME_SC_INVALID_NS and adjust the code such that
request will have the right status on nvmet_find_namespace() failure.

Without this patch :-
# nvme id-ns /dev/nvme1 -n 3
NVME Identify Namespace 3:
nsze    : 0
ncap    : 0
nuse    : 0
nsfeat  : 0
nlbaf   : 0
flbas   : 0
mc      : 0
dpc     : 0
dps     : 0
nmic    : 0
rescap  : 0
fpi     : 0
dlfeat  : 0
nawun   : 0
nawupf  : 0
nacwu   : 0
nabsn   : 0
nabo    : 0
nabspf  : 0
noiob   : 0
nvmcap  : 0
mssrl   : 0
mcl     : 0
msrc    : 0
nsattr	: 0
nvmsetid: 0
anagrpid: 0
endgid  : 0
nguid   : 00000000000000000000000000000000
eui64   : 0000000000000000
lbaf  0 : ms:0   lbads:0  rp:0 (in use)

With this patch-series :-

# gitlog -4
3fd4a1736f35 (HEAD -> nvme-5.11) nvmet: set right status on error in id-ns handler
4d8a9ebec05e nvmet: remove extra variable in id-desclist
de9e611ac167 nvmet: remove extra variable in identify ns
54165b5c1ca3 nvmet: remove extra variable in smart log nsid
# nvme id-ns /dev/nvme1 -n 3
NVMe status: INVALID_NS: The namespace or the format of that namespace is invalid(0xb)

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/target/admin-cmd.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index 955ca5a653fb..220edacfccfb 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -484,8 +484,10 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req)
 
 	/* return an all zeroed buffer if we can't find an active namespace */
 	req->ns = nvmet_find_namespace(ctrl, req->cmd->identify.nsid);
-	if (!req->ns)
+	if (!req->ns) {
+		status = NVME_SC_INVALID_NS;
 		goto done;
+	}
 
 	nvmet_ns_revalidate(req->ns);
 
@@ -538,7 +540,11 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req)
 	if (req->ns->readonly)
 		id->nsattr |= (1 << 0);
 done:
-	status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id));
+	if (nvmet_copy_to_sgl(req, 0, id, sizeof(*id))) {
+		if (!status)
+			status = NVME_SC_SGL_INVALID_DATA | NVME_SC_DNR;
+	}
+
 	kfree(id);
 out:
 	nvmet_req_complete(req, status);
-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Mon Jan  4 00:09:29 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Sun,  3 Jan 2021 21:09:29 -0800
Subject: [PATCH V8 0/9] nvmet: add ZBD backend support 
Message-ID: <20210104050938.25745-1-chaitanya.kulkarni@wdc.com>

Hi,

NVMeOF Host is capable of handling the NVMe Protocol based Zoned Block
Devices (ZBD) in the Zoned Namespaces (ZNS) mode with the passthru
backend. There is no support for a generic block device backend to
handle the ZBD devices which are not NVMe protocol compliant.

This adds support to export the ZBDs (which are not NVMe drives) to host
the from target via NVMeOF using the host side ZNS interface.

The patch series is generated in bottom-top manner where, it first adds
prep patch and ZNS command-specific handlers on the top of genblk and 
updates the data structures, then one by one it wires up the admin cmds
in the order host calls them in namespace initializing sequence. Once
everything is ready, it wires-up the I/O command handlers. See below for
patch-series overview.

All the testcases are passing for the ZoneFS where ZBD exported with
NVMeOF backed by null_blk ZBD and null_blk ZBD without NVMeOF. Adding
test result below.

Note: This patch-series is based on the earlier posted patch series :-

[PATCH 0/4] nvmet: admin-cmd related cleanups and a fix

http://lists.infradead.org/pipermail/linux-nvme/2021-January/021729.html

-ck

Changes from V7:-

1. Just like what block layer provides an API for bio_init(), provide
   nvmet_bio_init() such that we move bio initialization code for
   nvme-read-write commands from bdev and zns backend into the centralize
   helper. 
2. With bdev/zns/file now we have three backends that are checking for
   req->sg_cnt and calling nvmet_check_transfer_len() before we process
   nvme-read-write commands. Move this duplicate code from three
   backeneds into the helper.
3. Export and use nvmet_bio_done() callback in
   nvmet_execute_zone_append() instead of the open coding the function.
   This also avoids code duplication for bio & request completion with
   error log page update.
4. Add zonefs tests log for dm linear device created on the top of SMR HDD
   exported with NVMeOF ZNS backend with the help of nvme-loop.

Changes from V6:-

1. Instead of calling report zones to find conventional zones in the 
   loop use the loop inside LLD blkdev_report_zones()->LLD_report_zones,
   that also simplifies the report zone callback.
2. Fix the bug in nvmet_bdev_has_conv_zones().
3. Remove conditional operators in the nvmet_bdev_execute_zone_append().

Changes from V5:-

1.  Use bio->bi_iter.bi_sector for result of the REQ_OP_ZONE_APPEND
    command.
2.  Add endianness to the helper nvmet_sect_to_lba().
3.  Make bufsize u32 in zone mgmt recv command handler.
4.  Add __GFP_ZERO for report zone data buffer to return clean buffer.

Changes from V4:-

1.  Don't use bio_iov_iter_get_pages() instead add a patch to export
    bio_add_hw_page() and call it directly for zone append.
2.  Add inline vector optimization for append bio.
3.  Update the commit logs for the patches.
4.  Remove ZNS related identify data structures, use individual members.
5.  Add a comment for macro NVMET_MPSMIN_SHIFT.
6.  Remove nvmet_bdev() helper.
7.  Move the command set identifier code into common code.
8.  Use IS_ENABLED() and move helpers fomr zns.c into common code.
9.  Add a patch to support Command Set identifiers.
10. Open code nvmet_bdev_validate_zns_zones().
11. Remove the per namespace min zasl calculation and don't allow
    namespaces with zasl value > the first ns zasl value.
12. Move the stubs into the header file.
13. Add lba to/from sector conversion helpers and update the
    io-cmd-bdev.c to avoid the code duplication.
14. Add everything into one patch for zns command handlers and 
    respective calls from the target code.
15. Remove the trim ns-desclist admin callback patch from this series.
16. Add bio get and put helpers patches to reduce the duplicate code in
    generic bdev, passthru, and generic zns backend.

Changes from V3:-

1.  Get rid of the bio_max_zasl check.
2.  Remove extra lines.
4.  Remove the block layer api export patch.
5.  Remove the bvec check in the bio_iov_iter_get_pages() for
    REQ_OP_ZONE_APPEND so that we can reuse the code.

Changes from V2:-

1.  Move conventional zone bitmap check into 
    nvmet_bdev_validate_zns_zones(). 
2.  Don't use report zones call to check the runt zone.
3.  Trim nvmet_zasl() helper.
4.  Fix typo in the nvmet_zns_update_zasl().
5.  Remove the comment and fix the mdts calculation in
    nvmet_execute_identify_cns_cs_ctrl().
6.  Use u64 for bufsize in nvmet_bdev_execute_zone_mgmt_recv().
7.  Remove nvmet_zones_to_desc_size() and fix the nr_zones
    calculation.
8.  Remove the op variable in nvmet_bdev_execute_zone_append().
9.  Fix the nr_zones calculation nvmet_bdev_execute_zone_mgmt_recv().
10. Update cover letter subject.

Changes from V1:-

1.  Remove the nvmet-$(CONFIG_BLK_DEV_ZONED) += zns.o.
2.  Mark helpers inline.
3.  Fix typos in the comments and update the comments.
4.  Get rid of the curly brackets.
5.  Don't allow drives with last smaller zones.
6.  Calculate the zasl as a function of ax_zone_append_sectors,
    bio_max_pages so we don't have to split the bio.
7.  Add global subsys->zasl and update the zasl when new namespace
    is enabled.
8.  Rmove the loop in the nvmet_bdev_execute_zone_mgmt_recv() and
    move functionality in to the report zone callback.
9.  Add goto for default case in nvmet_bdev_execute_zone_mgmt_send().
10. Allocate the zones buffer with zones size instead of bdev nr_zones.

Chaitanya Kulkarni (9):
  block: export bio_add_hw_pages()
  nvmet: add lba to sect conversion helpers
  nvmet: add NVM command set identifier support
  nvmet: add ZBD over ZNS backend support
  nvmet: add bio get helper for different backends
  nvmet: add bio init helper for different backends
  nvmet: add bio put helper for different backends
  nvmet: add common I/O length check helper
  nvmet: call nvmet_bio_done() for zone append

 block/bio.c                       |   1 +
 block/blk.h                       |   4 -
 drivers/nvme/target/Makefile      |   1 +
 drivers/nvme/target/admin-cmd.c   |  59 ++++--
 drivers/nvme/target/core.c        |  14 +-
 drivers/nvme/target/io-cmd-bdev.c |  67 +++---
 drivers/nvme/target/io-cmd-file.c |   7 +-
 drivers/nvme/target/nvmet.h       |  97 +++++++++
 drivers/nvme/target/passthru.c    |  11 +-
 drivers/nvme/target/zns.c         | 328 ++++++++++++++++++++++++++++++
 include/linux/blkdev.h            |   4 +
 11 files changed, 526 insertions(+), 67 deletions(-)
 create mode 100644 drivers/nvme/target/zns.c

* Zonefs Test log with dm-linear on the top of SMR HDD:-
--------------------------------------------------------------------------------

1. Test Zoned Block Device info :- 
--------------------------------------------------------------------------------

# fdisk  -l /dev/sdh
Disk /dev/sdh: 13.64 TiB, 15000173281280 bytes, 3662151680 sectors
Disk model: HGST HSH721415AL
Units: sectors of 1 * 4096 = 4096 bytes
Sector size (logical/physical): 4096 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
# cat /sys/block/sdh/queue/nr_zones
55880
# cat /sys/block/sdh/queue/zoned
host-managed
# cat /sys/block/sdh/queue/zone_append_max_bytes
688128

2. Creating NVMeOF target backed by ZBD with dm-linear
--------------------------------------------------------------------------------

# ./zbdev.sh 1 dm-zbd
++ NQN=dm-zbd
++ echo '0 29022486528 linear /dev/sdh 274726912' | dmsetup create cksdh
9 directories, 4 files
++ mkdir /sys/kernel/config/nvmet/subsystems/dm-zbd
++ mkdir /sys/kernel/config/nvmet/subsystems/dm-zbd/namespaces/1
++ echo -n /dev/dm-0
++ cat /sys/kernel/config/nvmet/subsystems/dm-zbd/namespaces/1/device_path
/dev/dm-0
++ echo 1
++ mkdir /sys/kernel/config/nvmet/ports/1/
++ echo -n loop
++ echo -n 1
++ ln -s /sys/kernel/config/nvmet/subsystems/dm-zbd /sys/kernel/config/nvmet/ports/1/subsystems/
++ sleep 1
++ echo transport=loop,nqn=dm-zbd
++ sleep 1
++ dmesg -c
[233450.572565] nvmet: adding nsid 1 to subsystem dm-zbd
[233452.269477] nvmet: creating controller 1 for subsystem dm-zbd for NQN nqn.2014-08.org.nvmexpress:uuid:853d7e82-8018-44ce-8784-ab81e7465ad9.
[233452.283352] nvme nvme0: Please enable CONFIG_NVME_MULTIPATH for full support of multi-port devices.
[233452.292805] nvme nvme0: creating 8 I/O queues.
[233452.299210] nvme nvme0: new ctrl: "dm-zbd"

3. dm-linear and backend SMR HDD association :-
--------------------------------------------------------------------------------

# cat /sys/kernel/config/nvmet/subsystems/dm-zbd/namespaces/1/device_path 
/dev/dm-0
# dmsetup ls --tree
 cksdh (252:0)
	 ?? (8:112)
# lsblk | head -3
NAME    MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sdh       8:112  0  13.6T  0 disk 
??cksdh 252:0    0  13.5T  0 dm   

4. NVMeOF controller :- 
--------------------------------------------------------------------------------

# nvme list | tr -s ' ' ' '  
Node SN Model Namespace Usage Format FW Rev  
/dev/nvme0n1 8c6f348dcd64404c Linux 1 14.86 TB / 14.86 TB 4 KiB + 0 B 5.10.0nv

5. Zonefs tests results :-
--------------------------------------------------------------------------------

# ./zonefs-tests.sh /dev/nvme0n1 
Gathering information on /dev/nvme0n1...
zonefs-tests on /dev/nvme0n1:
  55356 zones (0 conventional zones, 55356 sequential zones)
  524288 512B sectors zone size (256 MiB)
  1 max open zones
Running tests
  Test 0010:  mkzonefs (options)                                   ... PASS
  Test 0011:  mkzonefs (force format)                              ... PASS
  Test 0012:  mkzonefs (invalid device)                            ... PASS
  Test 0013:  mkzonefs (super block zone state)                    ... PASS
  Test 0020:  mount (default)                                      ... PASS
  Test 0021:  mount (invalid device)                               ... PASS
  Test 0022:  mount (check mount directory sub-directories)        ... PASS
  Test 0023:  mount (options)                                      ... PASS
  Test 0030:  Number of files (default)                            ... PASS
  Test 0031:  Number of files (aggr_cnv)                           ... skip
  Test 0032:  Number of files using stat (default)                 ... PASS
  Test 0033:  Number of files using stat (aggr_cnv)                ... PASS
  Test 0034:  Number of blocks using stat (default)                ... PASS
  Test 0035:  Number of blocks using stat (aggr_cnv)               ... PASS
  Test 0040:  Files permissions (default)                          ... PASS
  Test 0041:  Files permissions (aggr_cnv)                         ... skip
  Test 0042:  Files permissions (set value)                        ... PASS
  Test 0043:  Files permissions (set value + aggr_cnv)             ... skip
  Test 0050:  Files owner (default)                                ... PASS
  Test 0051:  Files owner (aggr_cnv)                               ... skip
  Test 0052:  Files owner (set value)                              ... PASS
  Test 0053:  Files owner (set value + aggr_cnv)                   ... skip
  Test 0060:  Files size (default)                                 ... PASS
  Test 0061:  Files size (aggr_cnv)                                ... skip
  Test 0070:  Conventional file truncate                           ... skip
  Test 0071:  Conventional file truncate (aggr_cnv)                ... skip
  Test 0072:  Conventional file unlink                             ... skip
  Test 0073:  Conventional file unlink (aggr_cnv)                  ... skip
  Test 0074:  Conventional file random write                       ... skip
  Test 0075:  Conventional file random write (direct)              ... skip
  Test 0076:  Conventional file random write (aggr_cnv)            ... skip
  Test 0077:  Conventional file random write (aggr_cnv, direct)    ... skip
  Test 0078:  Conventional file mmap read/write                    ... skip
  Test 0079:  Conventional file mmap read/write (aggr_cnv)         ... skip
  Test 0080:  Sequential file truncate                             ... PASS
  Test 0081:  Sequential file unlink                               ... PASS
  Test 0082:  Sequential file buffered write IO                    ... PASS
  Test 0083:  Sequential file overwrite                            ... PASS
  Test 0084:  Sequential file unaligned write (sync IO)            ... PASS
  Test 0085:  Sequential file unaligned write (async IO)           ... PASS
  Test 0086:  Sequential file append (sync)                        ... PASS
  Test 0087:  Sequential file append (async)                       ... PASS
  Test 0088:  Sequential file random read                          ... PASS
  Test 0089:  Sequential file mmap read/write                      ... PASS
  Test 0090:  sequential file 4K synchronous write                 ... PASS
  Test 0091:  Sequential file large synchronous write              ... PASS

46 / 46 tests passed

* Without CONFIG_BLK_DEV_ZONED nvme tests :-
--------------------------------------------------------------------------------

#
# grep -i blk_dev_zoned .config
# CONFIG_BLK_DEV_ZONED is not set
# makej M=drivers/nvme/ clean 
  CLEAN   drivers/nvme//Module.symvers
# makej M=drivers/nvme/ 
  CC [M]  drivers/nvme//host/core.o
  CC [M]  drivers/nvme//host/trace.o
  CC [M]  drivers/nvme//host/lightnvm.o
  CC [M]  drivers/nvme//target/core.o
  CC [M]  drivers/nvme//host/hwmon.o
  CC [M]  drivers/nvme//target/configfs.o
  CC [M]  drivers/nvme//host/pci.o
  CC [M]  drivers/nvme//target/admin-cmd.o
  CC [M]  drivers/nvme//host/fabrics.o
  CC [M]  drivers/nvme//host/rdma.o
  CC [M]  drivers/nvme//target/fabrics-cmd.o
  CC [M]  drivers/nvme//target/discovery.o
  CC [M]  drivers/nvme//host/fc.o
  CC [M]  drivers/nvme//target/io-cmd-file.o
  CC [M]  drivers/nvme//host/tcp.o
  CC [M]  drivers/nvme//target/io-cmd-bdev.o
  CC [M]  drivers/nvme//target/passthru.o
  CC [M]  drivers/nvme//target/trace.o
  CC [M]  drivers/nvme//target/loop.o
  CC [M]  drivers/nvme//target/rdma.o
  CC [M]  drivers/nvme//target/fc.o
  CC [M]  drivers/nvme//target/fcloop.o
  CC [M]  drivers/nvme//target/tcp.o
  LD [M]  drivers/nvme//target/nvme-loop.o
  LD [M]  drivers/nvme//target/nvme-fcloop.o
  LD [M]  drivers/nvme//target/nvmet-tcp.o
  LD [M]  drivers/nvme//host/nvme-fabrics.o
  LD [M]  drivers/nvme//host/nvme.o
  LD [M]  drivers/nvme//host/nvme-rdma.o
  LD [M]  drivers/nvme//target/nvmet-rdma.o
  LD [M]  drivers/nvme//target/nvmet.o
  LD [M]  drivers/nvme//target/nvmet-fc.o
  LD [M]  drivers/nvme//host/nvme-tcp.o
  LD [M]  drivers/nvme//host/nvme-fc.o
  LD [M]  drivers/nvme//host/nvme-core.o
  MODPOST drivers/nvme//Module.symvers
  CC [M]  drivers/nvme//host/nvme-core.mod.o
  CC [M]  drivers/nvme//host/nvme-fabrics.mod.o
  CC [M]  drivers/nvme//host/nvme-fc.mod.o
  CC [M]  drivers/nvme//host/nvme-rdma.mod.o
  CC [M]  drivers/nvme//host/nvme-tcp.mod.o
  CC [M]  drivers/nvme//host/nvme.mod.o
  CC [M]  drivers/nvme//target/nvme-fcloop.mod.o
  CC [M]  drivers/nvme//target/nvme-loop.mod.o
  CC [M]  drivers/nvme//target/nvmet-fc.mod.o
  CC [M]  drivers/nvme//target/nvmet-rdma.mod.o
  CC [M]  drivers/nvme//target/nvmet-tcp.mod.o
  CC [M]  drivers/nvme//target/nvmet.mod.o
  LD [M]  drivers/nvme//target/nvme-fcloop.ko
  LD [M]  drivers/nvme//host/nvme-tcp.ko
  LD [M]  drivers/nvme//host/nvme-core.ko
  LD [M]  drivers/nvme//target/nvmet-tcp.ko
  LD [M]  drivers/nvme//target/nvme-loop.ko
  LD [M]  drivers/nvme//target/nvmet-fc.ko
  LD [M]  drivers/nvme//host/nvme-fabrics.ko
  LD [M]  drivers/nvme//host/nvme-fc.ko
  LD [M]  drivers/nvme//target/nvmet-rdma.ko
  LD [M]  drivers/nvme//host/nvme-rdma.ko
  LD [M]  drivers/nvme//host/nvme.ko
  LD [M]  drivers/nvme//target/nvmet.ko
#
# cdblktests 
# ./check tests/nvme/
nvme/002 (create many subsystems and test discovery)         [passed]
    runtime    ...  27.640s
nvme/003 (test if we're sending keep-alives to a discovery controller) [passed]
    runtime  10.145s  ...  10.147s
nvme/004 (test nvme and nvmet UUID NS descriptors)           [passed]
    runtime  1.713s  ...  1.712s
nvme/005 (reset local loopback target)                       [not run]
    nvme_core module does not have parameter multipath
nvme/006 (create an NVMeOF target with a block device-backed ns) [passed]
    runtime  0.111s  ...  0.115s
nvme/007 (create an NVMeOF target with a file-backed ns)     [passed]
    runtime  0.081s  ...  0.069s
nvme/008 (create an NVMeOF host with a block device-backed ns) [passed]
    runtime  1.690s  ...  1.727s
nvme/009 (create an NVMeOF host with a file-backed ns)       [passed]
    runtime  1.659s  ...  1.661s
nvme/010 (run data verification fio job on NVMeOF block device-backed ns) [passed]
    runtime  28.781s  ...  30.166s
nvme/011 (run data verification fio job on NVMeOF file-backed ns) [passed]
    runtime  253.831s  ...  238.774s
nvme/012 (run mkfs and data verification fio job on NVMeOF block device-backed ns) [passed]
    runtime  40.003s  ...  68.076s
nvme/013 (run mkfs and data verification fio job on NVMeOF file-backed ns) [passed]
    runtime  272.649s  ...  283.720s
nvme/014 (flush a NVMeOF block device-backed ns)             [passed]
    runtime  21.772s  ...  21.397s
nvme/015 (unit test for NVMe flush for file backed ns)       [passed]
    runtime  21.908s  ...  18.622s
nvme/016 (create/delete many NVMeOF block device-backed ns and test discovery) [passed]
    runtime  15.860s  ...  18.313s
nvme/017 (create/delete many file-ns and test discovery)     [passed]
    runtime  16.470s  ...  18.374s
nvme/018 (unit test NVMe-oF out of range access on a file backend) [passed]
    runtime  1.665s  ...  1.890s
nvme/019 (test NVMe DSM Discard command on NVMeOF block-device ns) [passed]
    runtime  1.681s  ...  1.982s
nvme/020 (test NVMe DSM Discard command on NVMeOF file-backed ns) [passed]
    runtime  1.645s  ...  1.913s
nvme/021 (test NVMe list command on NVMeOF file-backed ns)   [passed]
    runtime  1.648s  ...  1.956s
nvme/022 (test NVMe reset command on NVMeOF file-backed ns)  [passed]
    runtime  2.063s  ...  2.553s
nvme/023 (test NVMe smart-log command on NVMeOF block-device ns) [passed]
    runtime  1.692s  ...  2.588s
nvme/024 (test NVMe smart-log command on NVMeOF file-backed ns) [passed]
    runtime  1.643s  ...  1.656s
nvme/025 (test NVMe effects-log command on NVMeOF file-backed ns) [passed]
    runtime  1.640s  ...  1.668s
nvme/026 (test NVMe ns-descs command on NVMeOF file-backed ns) [passed]
    runtime  1.643s  ...  1.961s
nvme/027 (test NVMe ns-rescan command on NVMeOF file-backed ns) [passed]
    runtime  1.641s  ...  1.677s
nvme/028 (test NVMe list-subsys command on NVMeOF file-backed ns) [passed]
    runtime  1.648s  ...  1.868s
nvme/029 (test userspace IO via nvme-cli read/write interface) [passed]
    runtime  1.982s  ...  2.703s
nvme/030 (ensure the discovery generation counter is updated appropriately) [passed]
    runtime  0.308s  ...  0.328s
nvme/031 (test deletion of NVMeOF controllers immediately after setup) [passed]
    runtime  5.432s  ...  7.495s
nvme/038 (test deletion of NVMeOF subsystem without enabling) [passed]
    runtime  0.053s  ...  0.046s

* With CONFIG_BLK_DEV_ZONED nvme and zonefs tests on membacked null_blk zoned :-
--------------------------------------------------------------------------------

# grep -i blk_dev_zoned .config
CONFIG_BLK_DEV_ZONED=y
# make M=drivers/nvme/ clean 
  CLEAN   drivers/nvme//Module.symvers
# make M=drivers/nvme/ 
  CC [M]  drivers/nvme//host/core.o
  CC [M]  drivers/nvme//host/trace.o
  CC [M]  drivers/nvme//host/lightnvm.o
  CC [M]  drivers/nvme//host/zns.o
  CC [M]  drivers/nvme//host/hwmon.o
  LD [M]  drivers/nvme//host/nvme-core.o
  CC [M]  drivers/nvme//host/pci.o
  LD [M]  drivers/nvme//host/nvme.o
  CC [M]  drivers/nvme//host/fabrics.o
  LD [M]  drivers/nvme//host/nvme-fabrics.o
  CC [M]  drivers/nvme//host/rdma.o
  LD [M]  drivers/nvme//host/nvme-rdma.o
  CC [M]  drivers/nvme//host/fc.o
  LD [M]  drivers/nvme//host/nvme-fc.o
  CC [M]  drivers/nvme//host/tcp.o
  LD [M]  drivers/nvme//host/nvme-tcp.o
  CC [M]  drivers/nvme//target/core.o
  CC [M]  drivers/nvme//target/configfs.o
  CC [M]  drivers/nvme//target/admin-cmd.o
  CC [M]  drivers/nvme//target/fabrics-cmd.o
  CC [M]  drivers/nvme//target/discovery.o
  CC [M]  drivers/nvme//target/io-cmd-file.o
  CC [M]  drivers/nvme//target/io-cmd-bdev.o
  CC [M]  drivers/nvme//target/passthru.o
  CC [M]  drivers/nvme//target/zns.o
  CC [M]  drivers/nvme//target/trace.o
  LD [M]  drivers/nvme//target/nvmet.o
  CC [M]  drivers/nvme//target/loop.o
  LD [M]  drivers/nvme//target/nvme-loop.o
  CC [M]  drivers/nvme//target/rdma.o
  LD [M]  drivers/nvme//target/nvmet-rdma.o
  CC [M]  drivers/nvme//target/fc.o
  LD [M]  drivers/nvme//target/nvmet-fc.o
  CC [M]  drivers/nvme//target/fcloop.o
  LD [M]  drivers/nvme//target/nvme-fcloop.o
  CC [M]  drivers/nvme//target/tcp.o
  LD [M]  drivers/nvme//target/nvmet-tcp.o
  MODPOST drivers/nvme//Module.symvers
  CC [M]  drivers/nvme//host/nvme-core.mod.o
  LD [M]  drivers/nvme//host/nvme-core.ko
  CC [M]  drivers/nvme//host/nvme-fabrics.mod.o
  LD [M]  drivers/nvme//host/nvme-fabrics.ko
  CC [M]  drivers/nvme//host/nvme-fc.mod.o
  LD [M]  drivers/nvme//host/nvme-fc.ko
  CC [M]  drivers/nvme//host/nvme-rdma.mod.o
  LD [M]  drivers/nvme//host/nvme-rdma.ko
  CC [M]  drivers/nvme//host/nvme-tcp.mod.o
  LD [M]  drivers/nvme//host/nvme-tcp.ko
  CC [M]  drivers/nvme//host/nvme.mod.o
  LD [M]  drivers/nvme//host/nvme.ko
  CC [M]  drivers/nvme//target/nvme-fcloop.mod.o
  LD [M]  drivers/nvme//target/nvme-fcloop.ko
  CC [M]  drivers/nvme//target/nvme-loop.mod.o
  LD [M]  drivers/nvme//target/nvme-loop.ko
  CC [M]  drivers/nvme//target/nvmet-fc.mod.o
  LD [M]  drivers/nvme//target/nvmet-fc.ko
  CC [M]  drivers/nvme//target/nvmet-rdma.mod.o
  LD [M]  drivers/nvme//target/nvmet-rdma.ko
  CC [M]  drivers/nvme//target/nvmet-tcp.mod.o
  LD [M]  drivers/nvme//target/nvmet-tcp.ko
  CC [M]  drivers/nvme//target/nvmet.mod.o
  LD [M]  drivers/nvme//target/nvmet.ko
# 
# cdblktests 
# ./check tests/nvme/
nvme/002 (create many subsystems and test discovery)         [passed]
    runtime  24.378s  ...  24.636s
nvme/003 (test if we're sending keep-alives to a discovery controller) [passed]
    runtime  10.133s  ...  10.152s
nvme/004 (test nvme and nvmet UUID NS descriptors)           [passed]
    runtime  2.463s  ...  2.478s
nvme/005 (reset local loopback target)                       [not run]
    nvme_core module does not have parameter multipath
nvme/006 (create an NVMeOF target with a block device-backed ns) [passed]
    runtime  0.095s  ...  0.122s
nvme/007 (create an NVMeOF target with a file-backed ns)     [passed]
    runtime  0.065s  ...  0.079s
nvme/008 (create an NVMeOF host with a block device-backed ns) [passed]
    runtime  2.473s  ...  2.501s
nvme/009 (create an NVMeOF host with a file-backed ns)       [passed]
    runtime  2.460s  ...  2.424s
nvme/010 (run data verification fio job on NVMeOF block device-backed ns) [passed]
    runtime  24.526s  ...  28.015s
nvme/011 (run data verification fio job on NVMeOF file-backed ns) [passed]
    runtime  265.967s  ...  282.717s
nvme/012 (run mkfs and data verification fio job on NVMeOF block device-backed ns) [passed]
    runtime  44.665s  ...  48.124s
nvme/013 (run mkfs and data verification fio job on NVMeOF file-backed ns) [passed]
    runtime  261.739s  ...  352.331s
nvme/014 (flush a NVMeOF block device-backed ns)             [passed]
    runtime  21.268s  ...  22.013s
nvme/015 (unit test for NVMe flush for file backed ns)       [passed]
    runtime  18.820s  ...  22.104s
nvme/016 (create/delete many NVMeOF block device-backed ns and test discovery) [passed]
    runtime  13.899s  ...  14.322s
nvme/017 (create/delete many file-ns and test discovery)     [passed]
    runtime  14.322s  ...  14.031s
nvme/018 (unit test NVMe-oF out of range access on a file backend) [passed]
    runtime  2.450s  ...  2.444s
nvme/019 (test NVMe DSM Discard command on NVMeOF block-device ns) [passed]
    runtime  2.475s  ...  2.489s
nvme/020 (test NVMe DSM Discard command on NVMeOF file-backed ns) [passed]
    runtime  2.410s  ...  2.448s
nvme/021 (test NVMe list command on NVMeOF file-backed ns)   [passed]
    runtime  2.441s  ...  2.439s
nvme/022 (test NVMe reset command on NVMeOF file-backed ns)  [passed]
    runtime  2.864s  ...  2.863s
nvme/023 (test NVMe smart-log command on NVMeOF block-device ns) [passed]
    runtime  2.465s  ...  2.446s
nvme/024 (test NVMe smart-log command on NVMeOF file-backed ns) [passed]
    runtime  2.416s  ...  2.411s
nvme/025 (test NVMe effects-log command on NVMeOF file-backed ns) [passed]
    runtime  2.419s  ...  2.748s
nvme/026 (test NVMe ns-descs command on NVMeOF file-backed ns) [passed]
    runtime  2.422s  ...  2.410s
nvme/027 (test NVMe ns-rescan command on NVMeOF file-backed ns) [passed]
    runtime  2.456s  ...  2.462s
nvme/028 (test NVMe list-subsys command on NVMeOF file-backed ns) [passed]
    runtime  2.427s  ...  2.429s
nvme/029 (test userspace IO via nvme-cli read/write interface) [passed]
    runtime  2.751s  ...  2.755s
nvme/030 (ensure the discovery generation counter is updated appropriately) [passed]
    runtime  0.346s  ...  0.357s
nvme/031 (test deletion of NVMeOF controllers immediately after setup) [passed]
    runtime  13.601s  ...  13.591s
nvme/038 (test deletion of NVMeOF subsystem without enabling) [passed]
    runtime  0.039s  ...  0.059s
#
# cdzonefstest 
# ./zonefs-tests.sh /dev/nvme1n1 
Gathering information on /dev/nvme1n1...
zonefs-tests on /dev/nvme1n1:
  16 zones (0 conventional zones, 16 sequential zones)
  131072 512B sectors zone size (64 MiB)
  1 max open zones
Running tests
  Test 0010:  mkzonefs (options)                                   ... PASS
  Test 0011:  mkzonefs (force format)                              ... PASS
  Test 0012:  mkzonefs (invalid device)                            ... PASS
  Test 0013:  mkzonefs (super block zone state)                    ... PASS
  Test 0020:  mount (default)                                      ... PASS
  Test 0021:  mount (invalid device)                               ... PASS
  Test 0022:  mount (check mount directory sub-directories)        ... PASS
  Test 0023:  mount (options)                                      ... PASS
  Test 0030:  Number of files (default)                            ... PASS
  Test 0031:  Number of files (aggr_cnv)                           ... skip
  Test 0032:  Number of files using stat (default)                 ... PASS
  Test 0033:  Number of files using stat (aggr_cnv)                ... PASS
  Test 0034:  Number of blocks using stat (default)                ... PASS
  Test 0035:  Number of blocks using stat (aggr_cnv)               ... PASS
  Test 0040:  Files permissions (default)                          ... PASS
  Test 0041:  Files permissions (aggr_cnv)                         ... skip
  Test 0042:  Files permissions (set value)                        ... PASS
  Test 0043:  Files permissions (set value + aggr_cnv)             ... skip
  Test 0050:  Files owner (default)                                ... PASS
  Test 0051:  Files owner (aggr_cnv)                               ... skip
  Test 0052:  Files owner (set value)                              ... PASS
  Test 0053:  Files owner (set value + aggr_cnv)                   ... skip
  Test 0060:  Files size (default)                                 ... PASS
  Test 0061:  Files size (aggr_cnv)                                ... skip
  Test 0070:  Conventional file truncate                           ... skip
  Test 0071:  Conventional file truncate (aggr_cnv)                ... skip
  Test 0072:  Conventional file unlink                             ... skip
  Test 0073:  Conventional file unlink (aggr_cnv)                  ... skip
  Test 0074:  Conventional file random write                       ... skip
  Test 0075:  Conventional file random write (direct)              ... skip
  Test 0076:  Conventional file random write (aggr_cnv)            ... skip
  Test 0077:  Conventional file random write (aggr_cnv, direct)    ... skip
  Test 0078:  Conventional file mmap read/write                    ... skip
  Test 0079:  Conventional file mmap read/write (aggr_cnv)         ... skip
  Test 0080:  Sequential file truncate                             ... PASS
  Test 0081:  Sequential file unlink                               ... PASS
  Test 0082:  Sequential file buffered write IO                    ... PASS
  Test 0083:  Sequential file overwrite                            ... PASS
  Test 0084:  Sequential file unaligned write (sync IO)            ... PASS
  Test 0085:  Sequential file unaligned write (async IO)           ... PASS
  Test 0086:  Sequential file append (sync)                        ... PASS
  Test 0087:  Sequential file append (async)                       ... PASS
  Test 0088:  Sequential file random read                          ... PASS
  Test 0089:  Sequential file mmap read/write                      ... PASS
  Test 0090:  sequential file 4K synchronous write                 ... PASS
  Test 0091:  Sequential file large synchronous write              ... PASS

46 / 46 tests passed

-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Mon Jan  4 00:09:30 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Sun,  3 Jan 2021 21:09:30 -0800
Subject: [PATCH V8 1/9] block: export bio_add_hw_pages()
In-Reply-To: <20210104050938.25745-1-chaitanya.kulkarni@wdc.com>
References: <20210104050938.25745-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210104050938.25745-2-chaitanya.kulkarni@wdc.com>

To implement the NVMe Zone Append command on the NVMeOF target side for
generic Zoned Block Devices with NVMe Zoned Namespaces interface, we
need to build the bios with hardware limitations, i.e. we use
bio_add_hw_page() with queue_max_zone_append_sectors() instead of
bio_add_page().

Without this API being exported NVMeOF target will require to use
bio_add_hw_page() caller bio_iov_iter_get_pages(). That results in
extra work which is inefficient.

Export the API so that NVMeOF ZBD over ZNS backend can use it to build
Zone Append bios.

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 block/bio.c            | 1 +
 block/blk.h            | 4 ----
 include/linux/blkdev.h | 4 ++++
 3 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/block/bio.c b/block/bio.c
index 1f2cc1fbe283..5cbd56b54f98 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -826,6 +826,7 @@ int bio_add_hw_page(struct request_queue *q, struct bio *bio,
 	bio->bi_iter.bi_size += len;
 	return len;
 }
+EXPORT_SYMBOL(bio_add_hw_page);
 
 /**
  * bio_add_pc_page	- attempt to add page to passthrough bio
diff --git a/block/blk.h b/block/blk.h
index 7550364c326c..200030b2d74f 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -351,8 +351,4 @@ int bdev_resize_partition(struct block_device *bdev, int partno,
 		sector_t start, sector_t length);
 int disk_expand_part_tbl(struct gendisk *disk, int target);
 
-int bio_add_hw_page(struct request_queue *q, struct bio *bio,
-		struct page *page, unsigned int len, unsigned int offset,
-		unsigned int max_sectors, bool *same_page);
-
 #endif /* BLK_INTERNAL_H */
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 070de09425ad..028ccc9bdf8d 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -2005,6 +2005,10 @@ struct block_device *I_BDEV(struct inode *inode);
 struct block_device *bdgrab(struct block_device *bdev);
 void bdput(struct block_device *);
 
+int bio_add_hw_page(struct request_queue *q, struct bio *bio,
+		struct page *page, unsigned int len, unsigned int offset,
+		unsigned int max_sectors, bool *same_page);
+
 #ifdef CONFIG_BLOCK
 void invalidate_bdev(struct block_device *bdev);
 int truncate_bdev_range(struct block_device *bdev, fmode_t mode, loff_t lstart,
-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Mon Jan  4 00:09:31 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Sun,  3 Jan 2021 21:09:31 -0800
Subject: [PATCH V8 2/9] nvmet: add lba to sect conversion helpers
In-Reply-To: <20210104050938.25745-1-chaitanya.kulkarni@wdc.com>
References: <20210104050938.25745-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210104050938.25745-3-chaitanya.kulkarni@wdc.com>

In this preparation patch, we add helpers to convert lbas to sectors & 
sectors to lba. This is needed to eliminate code duplication in the ZBD 
backend.

Use these helpers in the block device backend.

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/target/io-cmd-bdev.c |  8 +++-----
 drivers/nvme/target/nvmet.h       | 10 ++++++++++
 2 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
index 125dde3f410e..23095bdfce06 100644
--- a/drivers/nvme/target/io-cmd-bdev.c
+++ b/drivers/nvme/target/io-cmd-bdev.c
@@ -256,8 +256,7 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req)
 	if (is_pci_p2pdma_page(sg_page(req->sg)))
 		op |= REQ_NOMERGE;
 
-	sector = le64_to_cpu(req->cmd->rw.slba);
-	sector <<= (req->ns->blksize_shift - 9);
+	sector = nvmet_lba_to_sect(req->ns, req->cmd->rw.slba);
 
 	if (req->transfer_len <= NVMET_MAX_INLINE_DATA_LEN) {
 		bio = &req->b.inline_bio;
@@ -345,7 +344,7 @@ static u16 nvmet_bdev_discard_range(struct nvmet_req *req,
 	int ret;
 
 	ret = __blkdev_issue_discard(ns->bdev,
-			le64_to_cpu(range->slba) << (ns->blksize_shift - 9),
+			nvmet_lba_to_sect(ns, range->slba),
 			le32_to_cpu(range->nlb) << (ns->blksize_shift - 9),
 			GFP_KERNEL, 0, bio);
 	if (ret && ret != -EOPNOTSUPP) {
@@ -414,8 +413,7 @@ static void nvmet_bdev_execute_write_zeroes(struct nvmet_req *req)
 	if (!nvmet_check_transfer_len(req, 0))
 		return;
 
-	sector = le64_to_cpu(write_zeroes->slba) <<
-		(req->ns->blksize_shift - 9);
+	sector = nvmet_lba_to_sect(req->ns, write_zeroes->slba);
 	nr_sector = (((sector_t)le16_to_cpu(write_zeroes->length) + 1) <<
 		(req->ns->blksize_shift - 9));
 
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 592763732065..8776dd1a0490 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -603,4 +603,14 @@ static inline bool nvmet_ns_has_pi(struct nvmet_ns *ns)
 	return ns->pi_type && ns->metadata_size == sizeof(struct t10_pi_tuple);
 }
 
+static inline __le64 nvmet_sect_to_lba(struct nvmet_ns *ns, sector_t sect)
+{
+	return cpu_to_le64(sect >> (ns->blksize_shift - SECTOR_SHIFT));
+}
+
+static inline sector_t nvmet_lba_to_sect(struct nvmet_ns *ns, __le64 lba)
+{
+	return le64_to_cpu(lba) << (ns->blksize_shift - SECTOR_SHIFT);
+}
+
 #endif /* _NVMET_H */
-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Mon Jan  4 00:09:32 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Sun,  3 Jan 2021 21:09:32 -0800
Subject: [PATCH V8 3/9] nvmet: add NVM command set identifier support
In-Reply-To: <20210104050938.25745-1-chaitanya.kulkarni@wdc.com>
References: <20210104050938.25745-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210104050938.25745-4-chaitanya.kulkarni@wdc.com>

NVMe TP 4056 allows controller to support different command sets.
NVMeoF target currently only supports namespaces that contain
traditional logical blocks that may be randomly read and written. In
some applications there is value in exposing namespaces that contain
logical blocks that have special access rules (e.g. sequentially write
required namespace such as Zoned Namespace (ZNS)).

In order to support the Zoned Block Devices (ZBD) backend, controller
needs to have support for ZNS Command Set Identifier (CSI).

In this preparation patch, we adjust the code such that it can now 
support different command sets. We update the namespace data
structure to store the CSI value which defaults to NVME_CSI_NVM
which represents traditional logical blocks namespace type.

The CSI support is required to implement the ZBD backend over NVMe ZNS 
interface, since ZNS commands belongs to the different command set than
the default one.

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/target/admin-cmd.c | 33 ++++++++++++++++++++-------------
 drivers/nvme/target/core.c      | 13 ++++++++++++-
 drivers/nvme/target/nvmet.h     |  1 +
 3 files changed, 33 insertions(+), 14 deletions(-)

diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index 220edacfccfb..2e865bff893f 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -175,19 +175,26 @@ static void nvmet_execute_get_log_cmd_effects_ns(struct nvmet_req *req)
 	if (!log)
 		goto out;
 
-	log->acs[nvme_admin_get_log_page]	= cpu_to_le32(1 << 0);
-	log->acs[nvme_admin_identify]		= cpu_to_le32(1 << 0);
-	log->acs[nvme_admin_abort_cmd]		= cpu_to_le32(1 << 0);
-	log->acs[nvme_admin_set_features]	= cpu_to_le32(1 << 0);
-	log->acs[nvme_admin_get_features]	= cpu_to_le32(1 << 0);
-	log->acs[nvme_admin_async_event]	= cpu_to_le32(1 << 0);
-	log->acs[nvme_admin_keep_alive]		= cpu_to_le32(1 << 0);
-
-	log->iocs[nvme_cmd_read]		= cpu_to_le32(1 << 0);
-	log->iocs[nvme_cmd_write]		= cpu_to_le32(1 << 0);
-	log->iocs[nvme_cmd_flush]		= cpu_to_le32(1 << 0);
-	log->iocs[nvme_cmd_dsm]			= cpu_to_le32(1 << 0);
-	log->iocs[nvme_cmd_write_zeroes]	= cpu_to_le32(1 << 0);
+	switch (req->cmd->get_log_page.csi) {
+	case NVME_CSI_NVM:
+		log->acs[nvme_admin_get_log_page]	= cpu_to_le32(1 << 0);
+		log->acs[nvme_admin_identify]		= cpu_to_le32(1 << 0);
+		log->acs[nvme_admin_abort_cmd]		= cpu_to_le32(1 << 0);
+		log->acs[nvme_admin_set_features]	= cpu_to_le32(1 << 0);
+		log->acs[nvme_admin_get_features]	= cpu_to_le32(1 << 0);
+		log->acs[nvme_admin_async_event]	= cpu_to_le32(1 << 0);
+		log->acs[nvme_admin_keep_alive]		= cpu_to_le32(1 << 0);
+
+		log->iocs[nvme_cmd_read]		= cpu_to_le32(1 << 0);
+		log->iocs[nvme_cmd_write]		= cpu_to_le32(1 << 0);
+		log->iocs[nvme_cmd_flush]		= cpu_to_le32(1 << 0);
+		log->iocs[nvme_cmd_dsm]			= cpu_to_le32(1 << 0);
+		log->iocs[nvme_cmd_write_zeroes]	= cpu_to_le32(1 << 0);
+		break;
+	default:
+		status = NVME_SC_INVALID_LOG_PAGE;
+		break;
+	}
 
 	status = nvmet_copy_to_sgl(req, 0, log, sizeof(*log));
 
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index 8ce4d59cc9e7..672e4009f8d6 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -681,6 +681,7 @@ struct nvmet_ns *nvmet_ns_alloc(struct nvmet_subsys *subsys, u32 nsid)
 
 	uuid_gen(&ns->uuid);
 	ns->buffered_io = false;
+	ns->csi = NVME_CSI_NVM;
 
 	return ns;
 }
@@ -1103,6 +1104,16 @@ static inline u8 nvmet_cc_iocqes(u32 cc)
 	return (cc >> NVME_CC_IOCQES_SHIFT) & 0xf;
 }
 
+static inline bool nvmet_cc_css_check(u8 cc_css)
+{
+	switch (cc_css <<= NVME_CC_CSS_SHIFT) {
+	case NVME_CC_CSS_NVM:
+		return true;
+	default:
+		return false;
+	}
+}
+
 static void nvmet_start_ctrl(struct nvmet_ctrl *ctrl)
 {
 	lockdep_assert_held(&ctrl->lock);
@@ -1111,7 +1122,7 @@ static void nvmet_start_ctrl(struct nvmet_ctrl *ctrl)
 	    nvmet_cc_iocqes(ctrl->cc) != NVME_NVM_IOCQES ||
 	    nvmet_cc_mps(ctrl->cc) != 0 ||
 	    nvmet_cc_ams(ctrl->cc) != 0 ||
-	    nvmet_cc_css(ctrl->cc) != 0) {
+	    !nvmet_cc_css_check(nvmet_cc_css(ctrl->cc))) {
 		ctrl->csts = NVME_CSTS_CFS;
 		return;
 	}
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 8776dd1a0490..476b3cd91c65 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -81,6 +81,7 @@ struct nvmet_ns {
 	struct pci_dev		*p2p_dev;
 	int			pi_type;
 	int			metadata_size;
+	u8			csi;
 };
 
 static inline struct nvmet_ns *to_nvmet_ns(struct config_item *item)
-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Mon Jan  4 00:09:33 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Sun,  3 Jan 2021 21:09:33 -0800
Subject: [PATCH V8 4/9] nvmet: add ZBD over ZNS backend support
In-Reply-To: <20210104050938.25745-1-chaitanya.kulkarni@wdc.com>
References: <20210104050938.25745-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210104050938.25745-5-chaitanya.kulkarni@wdc.com>

NVMe TP 4053 ? Zoned Namespaces (ZNS) allows host software to
communicate with a non-volatile memory subsystem using zones for
NVMe protocol based controllers. NVMeOF already support the ZNS NVMe
Protocol compliant devices on the target in the passthru mode. There
are Generic zoned block devices like  Shingled Magnetic Recording (SMR)
HDDs that are not based on the NVMe protocol.

This patch adds ZNS backend to support the ZBDs for NVMeOF target.

This support includes implementing the new command set NVME_CSI_ZNS,
adding different command handlers for ZNS command set such as
NVMe Identify Controller, NVMe Identify Namespace, NVMe Zone Append,
NVMe Zone Management Send and NVMe Zone Management Receive.

With new command set identifier we also update the target command effects
logs to reflect the ZNS compliant commands.

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/target/Makefile      |   1 +
 drivers/nvme/target/admin-cmd.c   |  26 +++
 drivers/nvme/target/core.c        |   1 +
 drivers/nvme/target/io-cmd-bdev.c |  33 ++-
 drivers/nvme/target/nvmet.h       |  38 ++++
 drivers/nvme/target/zns.c         | 342 ++++++++++++++++++++++++++++++
 6 files changed, 433 insertions(+), 8 deletions(-)
 create mode 100644 drivers/nvme/target/zns.c

diff --git a/drivers/nvme/target/Makefile b/drivers/nvme/target/Makefile
index ebf91fc4c72e..9837e580fa7e 100644
--- a/drivers/nvme/target/Makefile
+++ b/drivers/nvme/target/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_NVME_TARGET_TCP)		+= nvmet-tcp.o
 nvmet-y		+= core.o configfs.o admin-cmd.o fabrics-cmd.o \
 			discovery.o io-cmd-file.o io-cmd-bdev.o
 nvmet-$(CONFIG_NVME_TARGET_PASSTHRU)	+= passthru.o
+nvmet-$(CONFIG_BLK_DEV_ZONED)		+= zns.o
 nvme-loop-y	+= loop.o
 nvmet-rdma-y	+= rdma.o
 nvmet-fc-y	+= fc.o
diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index 2e865bff893f..3d1c7ca620a2 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -191,6 +191,15 @@ static void nvmet_execute_get_log_cmd_effects_ns(struct nvmet_req *req)
 		log->iocs[nvme_cmd_dsm]			= cpu_to_le32(1 << 0);
 		log->iocs[nvme_cmd_write_zeroes]	= cpu_to_le32(1 << 0);
 		break;
+	case NVME_CSI_ZNS:
+		if (IS_ENABLED(CONFIG_BLK_DEV_ZONED)) {
+			u32 *iocs = log->iocs;
+
+			iocs[nvme_cmd_zone_append]	= cpu_to_le32(1 << 0);
+			iocs[nvme_cmd_zone_mgmt_send]	= cpu_to_le32(1 << 0);
+			iocs[nvme_cmd_zone_mgmt_recv]	= cpu_to_le32(1 << 0);
+		}
+		break;
 	default:
 		status = NVME_SC_INVALID_LOG_PAGE;
 		break;
@@ -613,6 +622,7 @@ static u16 nvmet_copy_ns_identifier(struct nvmet_req *req, u8 type, u8 len,
 
 static void nvmet_execute_identify_desclist(struct nvmet_req *req)
 {
+	u16 nvme_cis_zns = NVME_CSI_ZNS;
 	u16 status = 0;
 	off_t off = 0;
 
@@ -637,6 +647,14 @@ static void nvmet_execute_identify_desclist(struct nvmet_req *req)
 		if (status)
 			goto out;
 	}
+	if (IS_ENABLED(CONFIG_BLK_DEV_ZONED)) {
+		if (req->ns->csi == NVME_CSI_ZNS)
+			status = nvmet_copy_ns_identifier(req, NVME_NIDT_CSI,
+							  NVME_NIDT_CSI_LEN,
+							  &nvme_cis_zns, &off);
+		if (status)
+			goto out;
+	}
 
 	if (sg_zero_buffer(req->sg, req->sg_cnt, NVME_IDENTIFY_DATA_SIZE - off,
 			off) != NVME_IDENTIFY_DATA_SIZE - off)
@@ -654,8 +672,16 @@ static void nvmet_execute_identify(struct nvmet_req *req)
 	switch (req->cmd->identify.cns) {
 	case NVME_ID_CNS_NS:
 		return nvmet_execute_identify_ns(req);
+	case NVME_ID_CNS_CS_NS:
+		if (req->cmd->identify.csi == NVME_CSI_ZNS)
+			return nvmet_execute_identify_cns_cs_ns(req);
+		break;
 	case NVME_ID_CNS_CTRL:
 		return nvmet_execute_identify_ctrl(req);
+	case NVME_ID_CNS_CS_CTRL:
+		if (req->cmd->identify.csi == NVME_CSI_ZNS)
+			return nvmet_execute_identify_cns_cs_ctrl(req);
+		break;
 	case NVME_ID_CNS_NS_ACTIVE_LIST:
 		return nvmet_execute_identify_nslist(req);
 	case NVME_ID_CNS_NS_DESC_LIST:
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index 672e4009f8d6..17a99c7134dc 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -1107,6 +1107,7 @@ static inline u8 nvmet_cc_iocqes(u32 cc)
 static inline bool nvmet_cc_css_check(u8 cc_css)
 {
 	switch (cc_css <<= NVME_CC_CSS_SHIFT) {
+	case NVME_CC_CSS_CSI:
 	case NVME_CC_CSS_NVM:
 		return true;
 	default:
diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
index 23095bdfce06..6178ef643962 100644
--- a/drivers/nvme/target/io-cmd-bdev.c
+++ b/drivers/nvme/target/io-cmd-bdev.c
@@ -63,6 +63,14 @@ static void nvmet_bdev_ns_enable_integrity(struct nvmet_ns *ns)
 	}
 }
 
+void nvmet_bdev_ns_disable(struct nvmet_ns *ns)
+{
+	if (ns->bdev) {
+		blkdev_put(ns->bdev, FMODE_WRITE | FMODE_READ);
+		ns->bdev = NULL;
+	}
+}
+
 int nvmet_bdev_ns_enable(struct nvmet_ns *ns)
 {
 	int ret;
@@ -86,15 +94,15 @@ int nvmet_bdev_ns_enable(struct nvmet_ns *ns)
 	if (IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY_T10))
 		nvmet_bdev_ns_enable_integrity(ns);
 
-	return 0;
-}
-
-void nvmet_bdev_ns_disable(struct nvmet_ns *ns)
-{
-	if (ns->bdev) {
-		blkdev_put(ns->bdev, FMODE_WRITE | FMODE_READ);
-		ns->bdev = NULL;
+	if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) && bdev_is_zoned(ns->bdev)) {
+		if (!nvmet_bdev_zns_enable(ns)) {
+			nvmet_bdev_ns_disable(ns);
+			return -EINVAL;
+		}
+		ns->csi = NVME_CSI_ZNS;
 	}
+
+	return 0;
 }
 
 void nvmet_bdev_ns_revalidate(struct nvmet_ns *ns)
@@ -448,6 +456,15 @@ u16 nvmet_bdev_parse_io_cmd(struct nvmet_req *req)
 	case nvme_cmd_write_zeroes:
 		req->execute = nvmet_bdev_execute_write_zeroes;
 		return 0;
+	case nvme_cmd_zone_append:
+		req->execute = nvmet_bdev_execute_zone_append;
+		return 0;
+	case nvme_cmd_zone_mgmt_recv:
+		req->execute = nvmet_bdev_execute_zone_mgmt_recv;
+		return 0;
+	case nvme_cmd_zone_mgmt_send:
+		req->execute = nvmet_bdev_execute_zone_mgmt_send;
+		return 0;
 	default:
 		pr_err("unhandled cmd %d on qid %d\n", cmd->common.opcode,
 		       req->sq->qid);
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 476b3cd91c65..7361665585a2 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -252,6 +252,10 @@ struct nvmet_subsys {
 	unsigned int		admin_timeout;
 	unsigned int		io_timeout;
 #endif /* CONFIG_NVME_TARGET_PASSTHRU */
+
+#ifdef CONFIG_BLK_DEV_ZONED
+	u8			zasl;
+#endif /* CONFIG_BLK_DEV_ZONED */
 };
 
 static inline struct nvmet_subsys *to_subsys(struct config_item *item)
@@ -614,4 +618,38 @@ static inline sector_t nvmet_lba_to_sect(struct nvmet_ns *ns, __le64 lba)
 	return le64_to_cpu(lba) << (ns->blksize_shift - SECTOR_SHIFT);
 }
 
+#ifdef CONFIG_BLK_DEV_ZONED
+bool nvmet_bdev_zns_enable(struct nvmet_ns *ns);
+void nvmet_execute_identify_cns_cs_ctrl(struct nvmet_req *req);
+void nvmet_execute_identify_cns_cs_ns(struct nvmet_req *req);
+void nvmet_bdev_execute_zone_mgmt_recv(struct nvmet_req *req);
+void nvmet_bdev_execute_zone_mgmt_send(struct nvmet_req *req);
+void nvmet_bdev_execute_zone_append(struct nvmet_req *req);
+#else  /* CONFIG_BLK_DEV_ZONED */
+static inline bool nvmet_bdev_zns_enable(struct nvmet_ns *ns)
+{
+	return false;
+}
+static inline void
+nvmet_execute_identify_cns_cs_ctrl(struct nvmet_req *req)
+{
+}
+static inline void
+nvmet_execute_identify_cns_cs_ns(struct nvmet_req *req)
+{
+}
+static inline void
+nvmet_bdev_execute_zone_mgmt_recv(struct nvmet_req *req)
+{
+}
+static inline void
+nvmet_bdev_execute_zone_mgmt_send(struct nvmet_req *req)
+{
+}
+static inline void
+nvmet_bdev_execute_zone_append(struct nvmet_req *req)
+{
+}
+#endif /* CONFIG_BLK_DEV_ZONED */
+
 #endif /* _NVMET_H */
diff --git a/drivers/nvme/target/zns.c b/drivers/nvme/target/zns.c
new file mode 100644
index 000000000000..2a71f56e568d
--- /dev/null
+++ b/drivers/nvme/target/zns.c
@@ -0,0 +1,342 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * NVMe ZNS-ZBD command implementation.
+ * Copyright (c) 2020-2021 HGST, a Western Digital Company.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/nvme.h>
+#include <linux/blkdev.h>
+#include "nvmet.h"
+
+/*
+ * We set the Memory Page Size Minimum (MPSMIN) for target controller to 0
+ * which gets added by 12 in the nvme_enable_ctrl() which results in 2^12 = 4k
+ * as page_shift value. When calculating the ZASL use shift by 12.
+ */
+#define NVMET_MPSMIN_SHIFT	12
+
+static u16 nvmet_bdev_zns_checks(struct nvmet_req *req)
+{
+	u16 status = NVME_SC_SUCCESS;
+
+	if (!bdev_is_zoned(req->ns->bdev)) {
+		status = NVME_SC_INVALID_NS | NVME_SC_DNR;
+		goto out;
+	}
+
+	if (req->cmd->zmr.zra != NVME_ZRA_ZONE_REPORT) {
+		status = NVME_SC_INVALID_FIELD;
+		goto out;
+	}
+
+	if (req->cmd->zmr.zrasf != NVME_ZRASF_ZONE_REPORT_ALL) {
+		status = NVME_SC_INVALID_FIELD;
+		goto out;
+	}
+
+	if (req->cmd->zmr.pr != NVME_REPORT_ZONE_PARTIAL)
+		status = NVME_SC_INVALID_FIELD;
+
+out:
+	return status;
+}
+
+/*
+ *  ZNS related command implementation and helpers.
+ */
+
+static inline u8 nvmet_zasl(unsigned int zone_append_sects)
+{
+	/*
+	 * Zone Append Size Limit is the value experessed in the units
+	 * of minimum memory page size (i.e. 12) and is reported power of 2.
+	 */
+	return ilog2((zone_append_sects << 9) >> NVMET_MPSMIN_SHIFT);
+}
+
+static inline bool nvmet_zns_update_zasl(struct nvmet_ns *ns)
+{
+	struct request_queue *q = ns->bdev->bd_disk->queue;
+	u8 zasl = nvmet_zasl(queue_max_zone_append_sectors(q));
+
+	if (ns->subsys->zasl)
+		return ns->subsys->zasl < zasl ? false : true;
+
+	ns->subsys->zasl = zasl;
+	return true;
+}
+
+
+static int nvmet_bdev_validate_zns_zones_cb(struct blk_zone *z,
+					    unsigned int idx, void *data)
+{
+	if (z->type == BLK_ZONE_TYPE_CONVENTIONAL)
+		return -EOPNOTSUPP;
+	return 0;
+}
+
+static bool nvmet_bdev_has_conv_zones(struct block_device *bdev)
+{
+	int ret;
+
+	if (bdev->bd_disk->queue->conv_zones_bitmap)
+		return true;
+
+	ret = blkdev_report_zones(bdev, 0, blkdev_nr_zones(bdev->bd_disk),
+				  nvmet_bdev_validate_zns_zones_cb, NULL);
+
+	return ret < 0 ? true : false;
+}
+
+bool nvmet_bdev_zns_enable(struct nvmet_ns *ns)
+{
+	if (nvmet_bdev_has_conv_zones(ns->bdev))
+		return false;
+
+	/*
+	 * For ZBC and ZAC devices, writes into sequential zones must be aligned
+	 * to the device physical block size. So use this value as the logical
+	 * block size to avoid errors.
+	 */
+	ns->blksize_shift = blksize_bits(bdev_physical_block_size(ns->bdev));
+
+	if (!nvmet_zns_update_zasl(ns))
+		return false;
+
+	return !(get_capacity(ns->bdev->bd_disk) &
+			(bdev_zone_sectors(ns->bdev) - 1));
+}
+
+/*
+ * ZNS related Admin and I/O command handlers.
+ */
+void nvmet_execute_identify_cns_cs_ctrl(struct nvmet_req *req)
+{
+	u8 zasl = req->sq->ctrl->subsys->zasl;
+	struct nvmet_ctrl *ctrl = req->sq->ctrl;
+	struct nvme_id_ctrl_zns *id;
+	u16 status;
+
+	id = kzalloc(sizeof(*id), GFP_KERNEL);
+	if (!id) {
+		status = NVME_SC_INTERNAL;
+		goto out;
+	}
+
+	if (ctrl->ops->get_mdts)
+		id->zasl = min_t(u8, ctrl->ops->get_mdts(ctrl), zasl);
+	else
+		id->zasl = zasl;
+
+	status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id));
+
+	kfree(id);
+out:
+	nvmet_req_complete(req, status);
+}
+
+void nvmet_execute_identify_cns_cs_ns(struct nvmet_req *req)
+{
+	struct nvme_id_ns_zns *id_zns;
+	u16 status = NVME_SC_SUCCESS;
+	u64 zsze;
+
+	if (le32_to_cpu(req->cmd->identify.nsid) == NVME_NSID_ALL) {
+		req->error_loc = offsetof(struct nvme_identify, nsid);
+		status = NVME_SC_INVALID_NS | NVME_SC_DNR;
+		goto out;
+	}
+
+	id_zns = kzalloc(sizeof(*id_zns), GFP_KERNEL);
+	if (!id_zns) {
+		status = NVME_SC_INTERNAL;
+		goto out;
+	}
+
+	req->ns = nvmet_find_namespace(req->sq->ctrl, req->cmd->identify.nsid);
+	if (!req->ns) {
+		status = NVME_SC_INTERNAL;
+		goto done;
+	}
+
+	if (!bdev_is_zoned(req->ns->bdev)) {
+		req->error_loc = offsetof(struct nvme_identify, nsid);
+		status = NVME_SC_INVALID_NS | NVME_SC_DNR;
+		goto done;
+	}
+
+	nvmet_ns_revalidate(req->ns);
+	zsze = (bdev_zone_sectors(req->ns->bdev) << 9) >>
+					req->ns->blksize_shift;
+	id_zns->lbafe[0].zsze = cpu_to_le64(zsze);
+	id_zns->mor = cpu_to_le32(bdev_max_open_zones(req->ns->bdev));
+	id_zns->mar = cpu_to_le32(bdev_max_active_zones(req->ns->bdev));
+
+done:
+	status = nvmet_copy_to_sgl(req, 0, id_zns, sizeof(*id_zns));
+	kfree(id_zns);
+out:
+	nvmet_req_complete(req, status);
+}
+
+struct nvmet_report_zone_data {
+	struct nvmet_ns *ns;
+	struct nvme_zone_report *rz;
+};
+
+static int nvmet_bdev_report_zone_cb(struct blk_zone *z, unsigned int idx,
+				     void *data)
+{
+	struct nvmet_report_zone_data *report_zone_data = data;
+	struct nvme_zone_descriptor *entries = report_zone_data->rz->entries;
+	struct nvmet_ns *ns = report_zone_data->ns;
+
+	entries[idx].zcap = nvmet_sect_to_lba(ns, z->capacity);
+	entries[idx].zslba = nvmet_sect_to_lba(ns, z->start);
+	entries[idx].wp = nvmet_sect_to_lba(ns, z->wp);
+	entries[idx].za = z->reset ? 1 << 2 : 0;
+	entries[idx].zt = z->type;
+	entries[idx].zs = z->cond << 4;
+
+	return 0;
+}
+
+void nvmet_bdev_execute_zone_mgmt_recv(struct nvmet_req *req)
+{
+	sector_t sect = nvmet_lba_to_sect(req->ns, req->cmd->zmr.slba);
+	u32 bufsize = (le32_to_cpu(req->cmd->zmr.numd) + 1) << 2;
+	struct nvmet_report_zone_data data = { .ns = req->ns };
+	unsigned int nr_zones;
+	int reported_zones;
+	u16 status;
+
+	nr_zones = (bufsize - sizeof(struct nvme_zone_report)) /
+			sizeof(struct nvme_zone_descriptor);
+
+	status = nvmet_bdev_zns_checks(req);
+	if (status)
+		goto out;
+
+	data.rz = __vmalloc(bufsize, GFP_KERNEL | __GFP_NORETRY | __GFP_ZERO);
+	if (!data.rz) {
+		status = NVME_SC_INTERNAL;
+		goto out;
+	}
+
+	reported_zones = blkdev_report_zones(req->ns->bdev, sect, nr_zones,
+					     nvmet_bdev_report_zone_cb,
+					     &data);
+	if (reported_zones < 0) {
+		status = NVME_SC_INTERNAL;
+		goto out_free_report_zones;
+	}
+
+	data.rz->nr_zones = cpu_to_le64(reported_zones);
+
+	status = nvmet_copy_to_sgl(req, 0, data.rz, bufsize);
+
+out_free_report_zones:
+	kvfree(data.rz);
+out:
+	nvmet_req_complete(req, status);
+}
+
+void nvmet_bdev_execute_zone_mgmt_send(struct nvmet_req *req)
+{
+	sector_t sect = nvmet_lba_to_sect(req->ns, req->cmd->zms.slba);
+	sector_t nr_sect = bdev_zone_sectors(req->ns->bdev);
+	u16 status = NVME_SC_SUCCESS;
+	enum req_opf op;
+	int ret;
+
+	if (req->cmd->zms.select_all)
+		nr_sect = get_capacity(req->ns->bdev->bd_disk);
+
+	switch (req->cmd->zms.zsa) {
+	case NVME_ZONE_OPEN:
+		op = REQ_OP_ZONE_OPEN;
+		break;
+	case NVME_ZONE_CLOSE:
+		op = REQ_OP_ZONE_CLOSE;
+		break;
+	case NVME_ZONE_FINISH:
+		op = REQ_OP_ZONE_FINISH;
+		break;
+	case NVME_ZONE_RESET:
+		op = REQ_OP_ZONE_RESET;
+		break;
+	default:
+		status = NVME_SC_INVALID_FIELD;
+		goto out;
+	}
+
+	ret = blkdev_zone_mgmt(req->ns->bdev, op, sect, nr_sect, GFP_KERNEL);
+	if (ret)
+		status = NVME_SC_INTERNAL;
+out:
+	nvmet_req_complete(req, status);
+}
+
+void nvmet_bdev_execute_zone_append(struct nvmet_req *req)
+{
+	sector_t sect = nvmet_lba_to_sect(req->ns, req->cmd->rw.slba);
+	struct request_queue *q = req->ns->bdev->bd_disk->queue;
+	unsigned int max_sects = queue_max_zone_append_sectors(q);
+	u16 status = NVME_SC_SUCCESS;
+	unsigned int total_len = 0;
+	struct scatterlist *sg;
+	int ret = 0, sg_cnt;
+	struct bio *bio;
+
+	if (!nvmet_check_transfer_len(req, nvmet_rw_data_len(req)))
+		return;
+
+	if (!req->sg_cnt) {
+		nvmet_req_complete(req, 0);
+		return;
+	}
+
+	if (req->transfer_len <= NVMET_MAX_INLINE_DATA_LEN) {
+		bio = &req->b.inline_bio;
+		bio_init(bio, req->inline_bvec, ARRAY_SIZE(req->inline_bvec));
+	} else {
+		bio = bio_alloc(GFP_KERNEL, req->sg_cnt);
+	}
+
+	bio_set_dev(bio, req->ns->bdev);
+	bio->bi_iter.bi_sector = sect;
+	bio->bi_opf = REQ_OP_ZONE_APPEND | REQ_SYNC | REQ_IDLE;
+	if (req->cmd->rw.control & cpu_to_le16(NVME_RW_FUA))
+		bio->bi_opf |= REQ_FUA;
+
+	for_each_sg(req->sg, sg, req->sg_cnt, sg_cnt) {
+		struct page *p = sg_page(sg);
+		unsigned int l = sg->length;
+		unsigned int o = sg->offset;
+		bool same_page = false;
+
+		ret = bio_add_hw_page(q, bio, p, l, o, max_sects, &same_page);
+		if (ret != sg->length) {
+			status = NVME_SC_INTERNAL;
+			goto out_bio_put;
+		}
+		if (same_page)
+			put_page(p);
+
+		total_len += sg->length;
+	}
+
+	if (total_len != nvmet_rw_data_len(req)) {
+		status = NVME_SC_INTERNAL | NVME_SC_DNR;
+		goto out_bio_put;
+	}
+
+	ret = submit_bio_wait(bio);
+	req->cqe->result.u64 = nvmet_sect_to_lba(req->ns,
+						 bio->bi_iter.bi_sector);
+
+out_bio_put:
+	if (bio != &req->b.inline_bio)
+		bio_put(bio);
+	nvmet_req_complete(req, ret < 0 ? NVME_SC_INTERNAL : status);
+}
-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Mon Jan  4 00:09:34 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Sun,  3 Jan 2021 21:09:34 -0800
Subject: [PATCH V8 5/9] nvmet: add bio get helper for different backends
In-Reply-To: <20210104050938.25745-1-chaitanya.kulkarni@wdc.com>
References: <20210104050938.25745-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210104050938.25745-6-chaitanya.kulkarni@wdc.com>

With the addition of the zns backend now we have three different
backends with inline bio optimization. That leads to having duplicate
code for allocating or initializing the bio in all three backends:
generic bdev, passsthru, and generic zns.

Add a helper function to reduce the duplicate code such that helper
function accepts the bi_end_io callback which gets initialize for the
non-inline bio_alloc() case. This is due to the special case needed for
the passthru backend non-inline bio allocation bio_alloc() where we set
the bio->bi_end_io = bio_put, having this parameter avoids the extra
branch in the passthru fast path. For rest of the backends, we set the
same bi_end_io callback for inline and non-inline cases, that is for
generic bdev we set to nvmet_bio_done() and for generic zns we set to
NULL. ? ? ? ? ? ? ? ? ? ? ? ? ? ?

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/target/io-cmd-bdev.c |  7 +------
 drivers/nvme/target/nvmet.h       | 16 ++++++++++++++++
 drivers/nvme/target/passthru.c    |  8 +-------
 drivers/nvme/target/zns.c         |  8 +-------
 4 files changed, 19 insertions(+), 20 deletions(-)

diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
index 6178ef643962..72746e29cb0d 100644
--- a/drivers/nvme/target/io-cmd-bdev.c
+++ b/drivers/nvme/target/io-cmd-bdev.c
@@ -266,12 +266,7 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req)
 
 	sector = nvmet_lba_to_sect(req->ns, req->cmd->rw.slba);
 
-	if (req->transfer_len <= NVMET_MAX_INLINE_DATA_LEN) {
-		bio = &req->b.inline_bio;
-		bio_init(bio, req->inline_bvec, ARRAY_SIZE(req->inline_bvec));
-	} else {
-		bio = bio_alloc(GFP_KERNEL, min(sg_cnt, BIO_MAX_PAGES));
-	}
+	bio = nvmet_req_bio_get(req, NULL);
 	bio_set_dev(bio, req->ns->bdev);
 	bio->bi_iter.bi_sector = sector;
 	bio->bi_private = req;
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 7361665585a2..3fc84f79cce1 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -652,4 +652,20 @@ nvmet_bdev_execute_zone_append(struct nvmet_req *req)
 }
 #endif /* CONFIG_BLK_DEV_ZONED */
 
+static inline struct bio *nvmet_req_bio_get(struct nvmet_req *req,
+					    bio_end_io_t *bi_end_io)
+{
+	struct bio *bio;
+
+	if (req->transfer_len <= NVMET_MAX_INLINE_DATA_LEN) {
+		bio = &req->b.inline_bio;
+		bio_init(bio, req->inline_bvec, ARRAY_SIZE(req->inline_bvec));
+		return bio;
+	}
+
+	bio = bio_alloc(GFP_KERNEL, req->sg_cnt);
+	bio->bi_end_io = bi_end_io;
+	return bio;
+}
+
 #endif /* _NVMET_H */
diff --git a/drivers/nvme/target/passthru.c b/drivers/nvme/target/passthru.c
index b9776fc8f08f..54f765b566ee 100644
--- a/drivers/nvme/target/passthru.c
+++ b/drivers/nvme/target/passthru.c
@@ -194,13 +194,7 @@ static int nvmet_passthru_map_sg(struct nvmet_req *req, struct request *rq)
 	if (req->sg_cnt > BIO_MAX_PAGES)
 		return -EINVAL;
 
-	if (req->transfer_len <= NVMET_MAX_INLINE_DATA_LEN) {
-		bio = &req->p.inline_bio;
-		bio_init(bio, req->inline_bvec, ARRAY_SIZE(req->inline_bvec));
-	} else {
-		bio = bio_alloc(GFP_KERNEL, min(req->sg_cnt, BIO_MAX_PAGES));
-		bio->bi_end_io = bio_put;
-	}
+	bio = nvmet_req_bio_get(req, bio_put);
 	bio->bi_opf = req_op(rq);
 
 	for_each_sg(req->sg, sg, req->sg_cnt, i) {
diff --git a/drivers/nvme/target/zns.c b/drivers/nvme/target/zns.c
index 2a71f56e568d..c32e93a3c7e1 100644
--- a/drivers/nvme/target/zns.c
+++ b/drivers/nvme/target/zns.c
@@ -296,13 +296,7 @@ void nvmet_bdev_execute_zone_append(struct nvmet_req *req)
 		return;
 	}
 
-	if (req->transfer_len <= NVMET_MAX_INLINE_DATA_LEN) {
-		bio = &req->b.inline_bio;
-		bio_init(bio, req->inline_bvec, ARRAY_SIZE(req->inline_bvec));
-	} else {
-		bio = bio_alloc(GFP_KERNEL, req->sg_cnt);
-	}
-
+	bio = nvmet_req_bio_get(req, NULL);
 	bio_set_dev(bio, req->ns->bdev);
 	bio->bi_iter.bi_sector = sect;
 	bio->bi_opf = REQ_OP_ZONE_APPEND | REQ_SYNC | REQ_IDLE;
-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Mon Jan  4 00:09:35 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Sun,  3 Jan 2021 21:09:35 -0800
Subject: [PATCH V8 6/9] nvmet: add bio init helper for different backends
In-Reply-To: <20210104050938.25745-1-chaitanya.kulkarni@wdc.com>
References: <20210104050938.25745-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210104050938.25745-7-chaitanya.kulkarni@wdc.com>

With the addition of the zns backend now we have two different backends
with the same bio initialization code. That leads to having duplicate
code in two backends: generic bdev and generic zns.

Add a helper function to reduce the duplicate code such that helper
function initializes the various bio initialization parameters such as
bio block device, op flags, sector, end io callback, and private member,

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/target/io-cmd-bdev.c |  6 +-----
 drivers/nvme/target/nvmet.h       | 11 +++++++++++
 drivers/nvme/target/zns.c         |  6 +++---
 3 files changed, 15 insertions(+), 8 deletions(-)

diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
index 72746e29cb0d..b1fb0bb1f39f 100644
--- a/drivers/nvme/target/io-cmd-bdev.c
+++ b/drivers/nvme/target/io-cmd-bdev.c
@@ -267,11 +267,7 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req)
 	sector = nvmet_lba_to_sect(req->ns, req->cmd->rw.slba);
 
 	bio = nvmet_req_bio_get(req, NULL);
-	bio_set_dev(bio, req->ns->bdev);
-	bio->bi_iter.bi_sector = sector;
-	bio->bi_private = req;
-	bio->bi_end_io = nvmet_bio_done;
-	bio->bi_opf = op;
+	nvmet_bio_init(bio, req->ns->bdev, op, sector, req, nvmet_bio_done);
 
 	blk_start_plug(&plug);
 	if (req->metadata_len)
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 3fc84f79cce1..1ec9e1b35c67 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -668,4 +668,15 @@ static inline struct bio *nvmet_req_bio_get(struct nvmet_req *req,
 	return bio;
 }
 
+static inline void nvmet_bio_init(struct bio *bio, struct block_device *bdev,
+				  unsigned int op, sector_t sect, void *private,
+				  bio_end_io_t *bi_end_io)
+{
+	bio_set_dev(bio, bdev);
+	bio->bi_opf = op;
+	bio->bi_iter.bi_sector = sect;
+	bio->bi_private = private;
+	bio->bi_end_io = bi_end_io;
+}
+
 #endif /* _NVMET_H */
diff --git a/drivers/nvme/target/zns.c b/drivers/nvme/target/zns.c
index c32e93a3c7e1..92213bed0006 100644
--- a/drivers/nvme/target/zns.c
+++ b/drivers/nvme/target/zns.c
@@ -281,6 +281,7 @@ void nvmet_bdev_execute_zone_append(struct nvmet_req *req)
 {
 	sector_t sect = nvmet_lba_to_sect(req->ns, req->cmd->rw.slba);
 	struct request_queue *q = req->ns->bdev->bd_disk->queue;
+	unsigned int op = REQ_OP_ZONE_APPEND | REQ_SYNC | REQ_IDLE;
 	unsigned int max_sects = queue_max_zone_append_sectors(q);
 	u16 status = NVME_SC_SUCCESS;
 	unsigned int total_len = 0;
@@ -297,9 +298,8 @@ void nvmet_bdev_execute_zone_append(struct nvmet_req *req)
 	}
 
 	bio = nvmet_req_bio_get(req, NULL);
-	bio_set_dev(bio, req->ns->bdev);
-	bio->bi_iter.bi_sector = sect;
-	bio->bi_opf = REQ_OP_ZONE_APPEND | REQ_SYNC | REQ_IDLE;
+	nvmet_bio_init(bio, req->ns->bdev, op, sect, NULL, NULL);
+
 	if (req->cmd->rw.control & cpu_to_le16(NVME_RW_FUA))
 		bio->bi_opf |= REQ_FUA;
 
-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Mon Jan  4 00:09:36 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Sun,  3 Jan 2021 21:09:36 -0800
Subject: [PATCH V8 7/9] nvmet: add bio put helper for different backends
In-Reply-To: <20210104050938.25745-1-chaitanya.kulkarni@wdc.com>
References: <20210104050938.25745-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210104050938.25745-8-chaitanya.kulkarni@wdc.com>

With the addition of zns backend now we have three different backends
with inline bio optimization. That leads to having duplicate code in for
freeing the bio in all three backends: generic bdev, passsthru and
generic zns.

Add a helper function to avoid the duplicate code and update the
respective backends.

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/target/io-cmd-bdev.c | 3 +--
 drivers/nvme/target/nvmet.h       | 6 ++++++
 drivers/nvme/target/passthru.c    | 3 +--
 drivers/nvme/target/zns.c         | 3 +--
 4 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
index b1fb0bb1f39f..562c2dd9c08c 100644
--- a/drivers/nvme/target/io-cmd-bdev.c
+++ b/drivers/nvme/target/io-cmd-bdev.c
@@ -172,8 +172,7 @@ static void nvmet_bio_done(struct bio *bio)
 	struct nvmet_req *req = bio->bi_private;
 
 	nvmet_req_complete(req, blk_to_nvme_status(req, bio->bi_status));
-	if (bio != &req->b.inline_bio)
-		bio_put(bio);
+	nvmet_req_bio_put(req, bio);
 }
 
 #ifdef CONFIG_BLK_DEV_INTEGRITY
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 1ec9e1b35c67..93ebc9ae3fe4 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -679,4 +679,10 @@ static inline void nvmet_bio_init(struct bio *bio, struct block_device *bdev,
 	bio->bi_end_io = bi_end_io;
 }
 
+static inline void nvmet_req_bio_put(struct nvmet_req *req, struct bio *bio)
+{
+	if (bio != &req->b.inline_bio)
+		bio_put(bio);
+}
+
 #endif /* _NVMET_H */
diff --git a/drivers/nvme/target/passthru.c b/drivers/nvme/target/passthru.c
index 54f765b566ee..a4a73d64c603 100644
--- a/drivers/nvme/target/passthru.c
+++ b/drivers/nvme/target/passthru.c
@@ -200,8 +200,7 @@ static int nvmet_passthru_map_sg(struct nvmet_req *req, struct request *rq)
 	for_each_sg(req->sg, sg, req->sg_cnt, i) {
 		if (bio_add_pc_page(rq->q, bio, sg_page(sg), sg->length,
 				    sg->offset) < sg->length) {
-			if (bio != &req->p.inline_bio)
-				bio_put(bio);
+			nvmet_req_bio_put(req, bio);
 			return -EINVAL;
 		}
 	}
diff --git a/drivers/nvme/target/zns.c b/drivers/nvme/target/zns.c
index 92213bed0006..bba1d6957b6a 100644
--- a/drivers/nvme/target/zns.c
+++ b/drivers/nvme/target/zns.c
@@ -330,7 +330,6 @@ void nvmet_bdev_execute_zone_append(struct nvmet_req *req)
 						 bio->bi_iter.bi_sector);
 
 out_bio_put:
-	if (bio != &req->b.inline_bio)
-		bio_put(bio);
+	nvmet_req_bio_put(req, bio);
 	nvmet_req_complete(req, ret < 0 ? NVME_SC_INTERNAL : status);
 }
-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Mon Jan  4 00:09:37 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Sun,  3 Jan 2021 21:09:37 -0800
Subject: [PATCH V8 8/9] nvmet: add common I/O length check helper
In-Reply-To: <20210104050938.25745-1-chaitanya.kulkarni@wdc.com>
References: <20210104050938.25745-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210104050938.25745-9-chaitanya.kulkarni@wdc.com>

With the addition of zns backend now we have three different
backends with which checks for the nvmet request's transfer len and
nvmet request's sg_cnt. That leads to having duplicate code in for
three backends: generic bdev, file and generic zns.

Add a helper function to avoid the duplicate code and update the
respective backends.

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/target/io-cmd-bdev.c |  8 +-------
 drivers/nvme/target/io-cmd-file.c |  7 +------
 drivers/nvme/target/nvmet.h       | 14 ++++++++++++++
 drivers/nvme/target/zns.c         |  7 +------
 4 files changed, 17 insertions(+), 19 deletions(-)

diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
index 562c2dd9c08c..c23a719513b0 100644
--- a/drivers/nvme/target/io-cmd-bdev.c
+++ b/drivers/nvme/target/io-cmd-bdev.c
@@ -240,16 +240,10 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req)
 	int op, i, rc;
 	struct sg_mapping_iter prot_miter;
 	unsigned int iter_flags;
-	unsigned int total_len = nvmet_rw_data_len(req) + req->metadata_len;
 
-	if (!nvmet_check_transfer_len(req, total_len))
+	if (!nvmet_continue_io(req, nvmet_rw_data_len(req) + req->metadata_len))
 		return;
 
-	if (!req->sg_cnt) {
-		nvmet_req_complete(req, 0);
-		return;
-	}
-
 	if (req->cmd->rw.opcode == nvme_cmd_write) {
 		op = REQ_OP_WRITE | REQ_SYNC | REQ_IDLE;
 		if (req->cmd->rw.control & cpu_to_le16(NVME_RW_FUA))
diff --git a/drivers/nvme/target/io-cmd-file.c b/drivers/nvme/target/io-cmd-file.c
index 0abbefd9925e..e7caff221b7b 100644
--- a/drivers/nvme/target/io-cmd-file.c
+++ b/drivers/nvme/target/io-cmd-file.c
@@ -241,14 +241,9 @@ static void nvmet_file_execute_rw(struct nvmet_req *req)
 {
 	ssize_t nr_bvec = req->sg_cnt;
 
-	if (!nvmet_check_transfer_len(req, nvmet_rw_data_len(req)))
+	if (!nvmet_continue_io(req, nvmet_rw_data_len(req)))
 		return;
 
-	if (!req->sg_cnt || !nr_bvec) {
-		nvmet_req_complete(req, 0);
-		return;
-	}
-
 	if (nr_bvec > NVMET_MAX_INLINE_BIOVEC)
 		req->f.bvec = kmalloc_array(nr_bvec, sizeof(struct bio_vec),
 				GFP_KERNEL);
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 93ebc9ae3fe4..f4f9d622df0d 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -685,4 +685,18 @@ static inline void nvmet_req_bio_put(struct nvmet_req *req, struct bio *bio)
 		bio_put(bio);
 }
 
+static inline bool nvmet_continue_io(struct nvmet_req *req,
+				     unsigned int total_len)
+{
+	if (!nvmet_check_transfer_len(req, total_len))
+		return false;
+
+	if (!req->sg_cnt) {
+		nvmet_req_complete(req, 0);
+		return false;
+	}
+
+	return true;
+}
+
 #endif /* _NVMET_H */
diff --git a/drivers/nvme/target/zns.c b/drivers/nvme/target/zns.c
index bba1d6957b6a..149bc8ce7010 100644
--- a/drivers/nvme/target/zns.c
+++ b/drivers/nvme/target/zns.c
@@ -289,14 +289,9 @@ void nvmet_bdev_execute_zone_append(struct nvmet_req *req)
 	int ret = 0, sg_cnt;
 	struct bio *bio;
 
-	if (!nvmet_check_transfer_len(req, nvmet_rw_data_len(req)))
+	if (!nvmet_continue_io(req, nvmet_rw_data_len(req)))
 		return;
 
-	if (!req->sg_cnt) {
-		nvmet_req_complete(req, 0);
-		return;
-	}
-
 	bio = nvmet_req_bio_get(req, NULL);
 	nvmet_bio_init(bio, req->ns->bdev, op, sect, NULL, NULL);
 
-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Mon Jan  4 00:09:38 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Sun,  3 Jan 2021 21:09:38 -0800
Subject: [PATCH V8 9/9] nvmet: call nvmet_bio_done() for zone append
In-Reply-To: <20210104050938.25745-1-chaitanya.kulkarni@wdc.com>
References: <20210104050938.25745-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210104050938.25745-10-chaitanya.kulkarni@wdc.com>

The function nvmet_bdev_execute_zone_append() does exactly same thing
for completion of the bio that is done in the nvmet_bio_done(),
completing the request & calling nvmet_bio_put()_to put non online bio.

Export the function nvmet_bio_done() and use that in the
nvmet_bdev_execute_zone_append() for the request completion and bio
processing. Set the bio->private after the call to submit_bio_wait() to
nvmet request. The call to nvmet_bio_done() also updates error log page
via call to blk_to_nvme_status() from nvmet_bio_done().

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/target/io-cmd-bdev.c |  2 +-
 drivers/nvme/target/nvmet.h       |  1 +
 drivers/nvme/target/zns.c         | 10 ++++------
 3 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
index c23a719513b0..72a22351da2a 100644
--- a/drivers/nvme/target/io-cmd-bdev.c
+++ b/drivers/nvme/target/io-cmd-bdev.c
@@ -167,7 +167,7 @@ static u16 blk_to_nvme_status(struct nvmet_req *req, blk_status_t blk_sts)
 	return status;
 }
 
-static void nvmet_bio_done(struct bio *bio)
+void nvmet_bio_done(struct bio *bio)
 {
 	struct nvmet_req *req = bio->bi_private;
 
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index f4f9d622df0d..ab84ab75b952 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -535,6 +535,7 @@ void nvmet_ns_changed(struct nvmet_subsys *subsys, u32 nsid);
 void nvmet_bdev_ns_revalidate(struct nvmet_ns *ns);
 int nvmet_file_ns_revalidate(struct nvmet_ns *ns);
 void nvmet_ns_revalidate(struct nvmet_ns *ns);
+void nvmet_bio_done(struct bio *bio);
 
 static inline u32 nvmet_rw_data_len(struct nvmet_req *req)
 {
diff --git a/drivers/nvme/target/zns.c b/drivers/nvme/target/zns.c
index 149bc8ce7010..da4be0231428 100644
--- a/drivers/nvme/target/zns.c
+++ b/drivers/nvme/target/zns.c
@@ -283,7 +283,6 @@ void nvmet_bdev_execute_zone_append(struct nvmet_req *req)
 	struct request_queue *q = req->ns->bdev->bd_disk->queue;
 	unsigned int op = REQ_OP_ZONE_APPEND | REQ_SYNC | REQ_IDLE;
 	unsigned int max_sects = queue_max_zone_append_sectors(q);
-	u16 status = NVME_SC_SUCCESS;
 	unsigned int total_len = 0;
 	struct scatterlist *sg;
 	int ret = 0, sg_cnt;
@@ -306,7 +305,7 @@ void nvmet_bdev_execute_zone_append(struct nvmet_req *req)
 
 		ret = bio_add_hw_page(q, bio, p, l, o, max_sects, &same_page);
 		if (ret != sg->length) {
-			status = NVME_SC_INTERNAL;
+			bio->bi_status = BLK_STS_IOERR;
 			goto out_bio_put;
 		}
 		if (same_page)
@@ -316,15 +315,14 @@ void nvmet_bdev_execute_zone_append(struct nvmet_req *req)
 	}
 
 	if (total_len != nvmet_rw_data_len(req)) {
-		status = NVME_SC_INTERNAL | NVME_SC_DNR;
+		bio->bi_status = BLK_STS_IOERR;
 		goto out_bio_put;
 	}
 
 	ret = submit_bio_wait(bio);
 	req->cqe->result.u64 = nvmet_sect_to_lba(req->ns,
 						 bio->bi_iter.bi_sector);
-
 out_bio_put:
-	nvmet_req_bio_put(req, bio);
-	nvmet_req_complete(req, ret < 0 ? NVME_SC_INTERNAL : status);
+	bio->bi_private = req;
+	nvmet_bio_done(bio);
 }
-- 
2.22.1



From selvakuma.s1 at samsung.com  Mon Jan  4 05:41:56 2021
From: selvakuma.s1 at samsung.com (SelvaKumar S)
Date: Mon,  4 Jan 2021 16:11:56 +0530
Subject: [RFC PATCH v4 0/3] add simple copy support
References: <CGME20210104104237epcas5p1ed2d167f50060eb0567ade5d9a1df701@epcas5p1.samsung.com>
Message-ID: <20210104104159.74236-1-selvakuma.s1@samsung.com>

This patchset tries to add support for TP4065a ("Simple Copy Command"),
v2020.05.04 ("Ratified")

The Specification can be found in following link.
https://nvmexpress.org/wp-content/uploads/NVM-Express-1.4-Ratified-TPs-1.zip

Simple copy command is a copy offloading operation and is  used to copy
multiple contiguous ranges (source_ranges) of LBA's to a single destination
LBA within the device reducing traffic between host and device.

This implementation doesn't add native copy offload support for stacked
devices rather copy offload is done through emulation. Possible use
cases are F2FS gc and BTRFS relocation/balance.

*blkdev_issue_copy* takes source bdev, no of sources, array of source
ranges(values are in bytes), destination bdev and destination offset(in bytes).
If both source and destination block devices are same and copy_offload = 1,
then copy is done through native copy offloading. Copy emulation is used
in other cases.

As SCSI XCOPY can take two different block devices and no of source range is
equal to 1, this interface can be extended in future to support SCSI XCOPY.

For devices supporting native simple copy, attach the control information
as payload to the bio and submit to the device. For devices without native
copy support, copy emulation is done by reading each source range into memory
and writing it to the destination.

Following limits are added to queue limits and are exposed in sysfs
to userspace
	- *copy_offload* controls copy_offload. set 0 to disable copy
		offload, 1 to enable native copy offloading support.
	- *max_copy_sectors* limits the sum of all source_range length
	- *max_copy_nr_ranges* limits the number of source ranges
	- *max_copy_range_sectors* limit the maximum number of sectors
		that can constitute a single source range.

	max_copy_sectors = 0 indicates the device doesn't support copy
offloading.

	*copy offload* sysfs entry is configurable and can be used toggle
between emulation and native support depending upon the usecase.

Changes from v3

1. gfp_flag fixes.
2. Export bio_map_kern() and use it to allocate and add pages to bio.
3. Move copy offload, reading to buf, writing from buf to separate functions.
4. Send read bio of copy offload by chaining them and submit asynchronously.
5. Add gendisk->part0 and part->bd_start_sect changes to blk_check_copy().
6. Move single source range limit check to blk_check_copy()
7. Rename __blkdev_issue_copy() to blkdev_issue_copy and remove old helper.
8. Change blkdev_issue_copy() interface generic to accepts destination bdev
	to support XCOPY as well.
9. Add invalidate_kernel_vmap_range() after reading data for vmalloc'ed memory.
10. Fix buf allocoation logic to allocate buffer for the total size of copy.
11. Reword patch commit description.

Changes from v2

1. Add emulation support for devices not supporting copy.
2. Add *copy_offload* sysfs entry to enable and disable copy_offload
	in devices supporting simple copy.
3. Remove simple copy support for stacked devices.

Changes from v1:

1. Fix memory leak in __blkdev_issue_copy
2. Unmark blk_check_copy inline
3. Fix line break in blk_check_copy_eod
4. Remove p checks and made code more readable
5. Don't use bio_set_op_attrs and remove op and set
   bi_opf directly
6. Use struct_size to calculate total_size
7. Fix partition remap of copy destination
8. Remove mcl,mssrl,msrc from nvme_ns
9. Initialize copy queue limits to 0 in nvme_config_copy
10. Remove return in QUEUE_FLAG_COPY check
11. Remove unused OCFS

SelvaKumar S (3):
  block: export bio_map_kern()
  block: add simple copy support
  nvme: add simple copy support

 block/blk-core.c          |  94 ++++++++++++++--
 block/blk-lib.c           | 223 ++++++++++++++++++++++++++++++++++++++
 block/blk-map.c           |   3 +-
 block/blk-merge.c         |   2 +
 block/blk-settings.c      |  10 ++
 block/blk-sysfs.c         |  50 +++++++++
 block/blk-zoned.c         |   1 +
 block/bounce.c            |   1 +
 block/ioctl.c             |  43 ++++++++
 drivers/nvme/host/core.c  |  87 +++++++++++++++
 include/linux/bio.h       |   1 +
 include/linux/blk_types.h |  15 +++
 include/linux/blkdev.h    |  15 +++
 include/linux/nvme.h      |  43 +++++++-
 include/uapi/linux/fs.h   |  13 +++
 15 files changed, 589 insertions(+), 12 deletions(-)

-- 
2.25.1



From selvakuma.s1 at samsung.com  Mon Jan  4 05:41:57 2021
From: selvakuma.s1 at samsung.com (SelvaKumar S)
Date: Mon,  4 Jan 2021 16:11:57 +0530
Subject: [RFC PATCH v4 1/3] block: export bio_map_kern()
In-Reply-To: <20210104104159.74236-1-selvakuma.s1@samsung.com>
References: <20210104104159.74236-1-selvakuma.s1@samsung.com>
 <CGME20210104104245epcas5p26ed395efbf74e78a4e44048a6d7d6ba7@epcas5p2.samsung.com>
Message-ID: <20210104104159.74236-2-selvakuma.s1@samsung.com>

Export bio_map_kern() so that copy offload emulation can use
it to add vmalloced memory to bio.

Signed-off-by: SelvaKumar S <selvakuma.s1 at samsung.com>
---
 block/blk-map.c        | 3 ++-
 include/linux/blkdev.h | 2 ++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/block/blk-map.c b/block/blk-map.c
index 21630dccac62..50d61475bb68 100644
--- a/block/blk-map.c
+++ b/block/blk-map.c
@@ -378,7 +378,7 @@ static void bio_map_kern_endio(struct bio *bio)
  *	Map the kernel address into a bio suitable for io to a block
  *	device. Returns an error pointer in case of error.
  */
-static struct bio *bio_map_kern(struct request_queue *q, void *data,
+struct bio *bio_map_kern(struct request_queue *q, void *data,
 		unsigned int len, gfp_t gfp_mask)
 {
 	unsigned long kaddr = (unsigned long)data;
@@ -428,6 +428,7 @@ static struct bio *bio_map_kern(struct request_queue *q, void *data,
 	bio->bi_end_io = bio_map_kern_endio;
 	return bio;
 }
+EXPORT_SYMBOL(bio_map_kern);
 
 static void bio_copy_kern_endio(struct bio *bio)
 {
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 070de09425ad..81f9e7bec16c 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -936,6 +936,8 @@ extern int blk_rq_map_user(struct request_queue *, struct request *,
 			   struct rq_map_data *, void __user *, unsigned long,
 			   gfp_t);
 extern int blk_rq_unmap_user(struct bio *);
+extern struct bio *bio_map_kern(struct request_queue *q, void *data,
+				unsigned int len, gfp_t gfp_mask);
 extern int blk_rq_map_kern(struct request_queue *, struct request *, void *, unsigned int, gfp_t);
 extern int blk_rq_map_user_iov(struct request_queue *, struct request *,
 			       struct rq_map_data *, const struct iov_iter *,
-- 
2.25.1



From selvakuma.s1 at samsung.com  Mon Jan  4 05:41:58 2021
From: selvakuma.s1 at samsung.com (SelvaKumar S)
Date: Mon,  4 Jan 2021 16:11:58 +0530
Subject: [RFC PATCH v4 2/3] block: add simple copy support
In-Reply-To: <20210104104159.74236-1-selvakuma.s1@samsung.com>
References: <20210104104159.74236-1-selvakuma.s1@samsung.com>
 <CGME20210104104249epcas5p458d1b5c39b5acfad4e7786eca5dd5c49@epcas5p4.samsung.com>
Message-ID: <20210104104159.74236-3-selvakuma.s1@samsung.com>

Add new BLKCOPY ioctl that offloads copying of one or more sources
ranges to a destination in the device. Accepts copy_ranges that contains
destination, no of sources and pointer to the array of source
ranges. Each range_entry contains start and length of source
ranges (in bytes).

Introduce REQ_OP_COPY, a no-merge copy offload operation. Create
bio with control information as payload and submit to the device.
REQ_OP_COPY(19) is a write op and takes zone_write_lock when submitted
to zoned device.

If the device doesn't support copy or copy offload is disabled, then
copy is emulated by allocating memory of total copy size. The source
ranges are read into memory by chaining bio for each source ranges and
submitting them async and the last bio waits for completion. After data
is read, it is written to the destination.

bio_map_kern() is used to allocate bio and add pages of copy buffer to
bio. As bio->bi_private and bio->bi_end_io is needed for chaining the
bio and over written, invalidate_kernel_vmap_range() for read is called
in the caller.

Introduce queue limits for simple copy and other helper functions.
Add device limits as sysfs entries.
	- copy_offload
	- max_copy_sectors
	- max_copy_ranges_sectors
	- max_copy_nr_ranges

copy_offload(= 0) is disabled by default.
max_copy_sectors = 0 indicates the device doesn't support native copy.

Native copy offload is not supported for stacked devices and is done via
copy emulation.

Signed-off-by: SelvaKumar S <selvakuma.s1 at samsung.com>
Signed-off-by: Kanchan Joshi <joshi.k at samsung.com>
Signed-off-by: Nitesh Shetty <nj.shetty at samsung.com>
Signed-off-by: Javier Gonz?lez <javier.gonz at samsung.com>
---
 block/blk-core.c          |  94 ++++++++++++++--
 block/blk-lib.c           | 223 ++++++++++++++++++++++++++++++++++++++
 block/blk-merge.c         |   2 +
 block/blk-settings.c      |  10 ++
 block/blk-sysfs.c         |  50 +++++++++
 block/blk-zoned.c         |   1 +
 block/bounce.c            |   1 +
 block/ioctl.c             |  43 ++++++++
 include/linux/bio.h       |   1 +
 include/linux/blk_types.h |  15 +++
 include/linux/blkdev.h    |  13 +++
 include/uapi/linux/fs.h   |  13 +++
 12 files changed, 458 insertions(+), 8 deletions(-)

diff --git a/block/blk-core.c b/block/blk-core.c
index 96e5fcd7f071..4a5cd3f53cd2 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -719,6 +719,17 @@ static noinline int should_fail_bio(struct bio *bio)
 }
 ALLOW_ERROR_INJECTION(should_fail_bio, ERRNO);
 
+static inline int bio_check_copy_eod(struct bio *bio, sector_t start,
+		sector_t nr_sectors, sector_t maxsector)
+{
+	if (nr_sectors && maxsector &&
+	    (nr_sectors > maxsector || start > maxsector - nr_sectors)) {
+		handle_bad_sector(bio, maxsector);
+		return -EIO;
+	}
+	return 0;
+}
+
 /*
  * Check whether this bio extends beyond the end of the device or partition.
  * This may well happen - the kernel calls bread() without checking the size of
@@ -737,6 +748,65 @@ static inline int bio_check_eod(struct bio *bio, sector_t maxsector)
 	return 0;
 }
 
+/*
+ * Check for copy limits and remap source ranges if needed.
+ */
+static int blk_check_copy(struct bio *bio)
+{
+	struct block_device *p = NULL;
+	struct request_queue *q = bio->bi_disk->queue;
+	struct blk_copy_payload *payload;
+	int i, maxsector, start_sect = 0, ret = -EIO;
+	unsigned short nr_range;
+
+	rcu_read_lock();
+
+	p = __disk_get_part(bio->bi_disk, bio->bi_partno);
+	if (unlikely(!p))
+		goto out;
+	if (unlikely(should_fail_request(p, bio->bi_iter.bi_size)))
+		goto out;
+	if (unlikely(bio_check_ro(bio, p)))
+		goto out;
+
+	maxsector =  bdev_nr_sectors(p);
+	start_sect = p->bd_start_sect;
+
+	payload = bio_data(bio);
+	nr_range = payload->copy_range;
+
+	/* cannot handle copy crossing nr_ranges limit */
+	if (payload->copy_range > q->limits.max_copy_nr_ranges)
+		goto out;
+
+	/* cannot handle copy more than copy limits */
+	if (payload->copy_size > q->limits.max_copy_sectors)
+		goto out;
+
+	/* check if copy length crosses eod */
+	if (unlikely(bio_check_copy_eod(bio, bio->bi_iter.bi_sector,
+					payload->copy_size, maxsector)))
+		goto out;
+	bio->bi_iter.bi_sector += start_sect;
+
+	for (i = 0; i < nr_range; i++) {
+		if (unlikely(bio_check_copy_eod(bio, payload->range[i].src,
+					payload->range[i].len, maxsector)))
+			goto out;
+
+		/* single source range length limit */
+		if (payload->range[i].src > q->limits.max_copy_range_sectors)
+			goto out;
+		payload->range[i].src += start_sect;
+	}
+
+	bio->bi_partno = 0;
+	ret = 0;
+out:
+	rcu_read_unlock();
+	return ret;
+}
+
 /*
  * Remap block n of partition p to block n+start(p) of the disk.
  */
@@ -826,14 +896,16 @@ static noinline_for_stack bool submit_bio_checks(struct bio *bio)
 	if (should_fail_bio(bio))
 		goto end_io;
 
-	if (bio->bi_partno) {
-		if (unlikely(blk_partition_remap(bio)))
-			goto end_io;
-	} else {
-		if (unlikely(bio_check_ro(bio, bio->bi_disk->part0)))
-			goto end_io;
-		if (unlikely(bio_check_eod(bio, get_capacity(bio->bi_disk))))
-			goto end_io;
+	if (likely(!op_is_copy(bio->bi_opf))) {
+		if (bio->bi_partno) {
+			if (unlikely(blk_partition_remap(bio)))
+				goto end_io;
+		} else {
+			if (unlikely(bio_check_ro(bio, bio->bi_disk->part0)))
+				goto end_io;
+			if (unlikely(bio_check_eod(bio, get_capacity(bio->bi_disk))))
+				goto end_io;
+		}
 	}
 
 	/*
@@ -857,6 +929,12 @@ static noinline_for_stack bool submit_bio_checks(struct bio *bio)
 		if (!blk_queue_discard(q))
 			goto not_supported;
 		break;
+	case REQ_OP_COPY:
+		if (!blk_queue_copy(q))
+			goto not_supported;
+		if (unlikely(blk_check_copy(bio)))
+			goto end_io;
+		break;
 	case REQ_OP_SECURE_ERASE:
 		if (!blk_queue_secure_erase(q))
 			goto not_supported;
diff --git a/block/blk-lib.c b/block/blk-lib.c
index 752f9c722062..4c0f12e2ed7c 100644
--- a/block/blk-lib.c
+++ b/block/blk-lib.c
@@ -150,6 +150,229 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
 }
 EXPORT_SYMBOL(blkdev_issue_discard);
 
+int blk_copy_offload(struct block_device *bdev, struct blk_copy_payload *payload,
+		sector_t dest, gfp_t gfp_mask)
+{
+	struct bio *bio;
+	int ret, total_size;
+
+	bio = bio_alloc(gfp_mask, 1);
+	bio->bi_iter.bi_sector = dest;
+	bio->bi_opf = REQ_OP_COPY | REQ_NOMERGE;
+	bio_set_dev(bio, bdev);
+
+	total_size = struct_size(payload, range, payload->copy_range);
+	ret = bio_add_page(bio, virt_to_page(payload), total_size,
+					   offset_in_page(payload));
+	if (ret != total_size) {
+		ret = -ENOMEM;
+		bio_put(bio);
+		goto err;
+	}
+
+	ret = submit_bio_wait(bio);
+err:
+	bio_put(bio);
+	return ret;
+
+}
+
+int blk_read_to_buf(struct block_device *bdev, struct blk_copy_payload *payload,
+		gfp_t gfp_mask, void **buf_p)
+{
+	struct request_queue *q = bdev_get_queue(bdev);
+	struct bio *bio, *parent = NULL;
+	void *buf = NULL;
+	bool is_vmalloc;
+	int i, nr_srcs, copy_len, ret, cur_size, t_len = 0;
+
+	nr_srcs = payload->copy_range;
+	copy_len = payload->copy_size << SECTOR_SHIFT;
+
+	buf = kvmalloc(copy_len, gfp_mask);
+	if (!buf)
+		return -ENOMEM;
+	is_vmalloc = is_vmalloc_addr(buf);
+
+	for (i = 0; i < nr_srcs; i++) {
+		cur_size = payload->range[i].len << SECTOR_SHIFT;
+
+		bio = bio_map_kern(q, buf + t_len, cur_size, gfp_mask);
+		if (IS_ERR(bio)) {
+			ret = PTR_ERR(bio);
+			goto out;
+		}
+
+		bio->bi_iter.bi_sector = payload->range[i].src;
+		bio->bi_opf = REQ_OP_READ;
+		bio_set_dev(bio, bdev);
+		bio->bi_end_io = NULL;
+		bio->bi_private = NULL;
+
+		if (parent) {
+			bio_chain(parent, bio);
+			submit_bio(parent);
+		}
+
+		parent = bio;
+		t_len += cur_size;
+	}
+
+	ret = submit_bio_wait(bio);
+	bio_put(bio);
+	if (is_vmalloc)
+		invalidate_kernel_vmap_range(buf, copy_len);
+	if (ret)
+		goto out;
+
+	*buf_p = buf;
+	return 0;
+out:
+	kvfree(buf);
+	return ret;
+}
+
+int blk_write_from_buf(struct block_device *bdev, void *buf, sector_t dest,
+		int copy_len, gfp_t gfp_mask)
+{
+	struct request_queue *q = bdev_get_queue(bdev);
+	struct bio *bio;
+	int ret;
+
+	bio = bio_map_kern(q, buf, copy_len, gfp_mask);
+	if (IS_ERR(bio)) {
+		ret = PTR_ERR(bio);
+		goto out;
+	}
+	bio_set_dev(bio, bdev);
+	bio->bi_opf = REQ_OP_WRITE;
+	bio->bi_iter.bi_sector = dest;
+
+	bio->bi_end_io = NULL;
+	ret = submit_bio_wait(bio);
+	bio_put(bio);
+out:
+	return ret;
+}
+
+int blk_prepare_payload(struct block_device *bdev, int nr_srcs, struct range_entry *rlist,
+		gfp_t gfp_mask, struct blk_copy_payload **payload_p)
+{
+
+	struct request_queue *q = bdev_get_queue(bdev);
+	struct blk_copy_payload *payload;
+	sector_t bs_mask;
+	sector_t src_sects, len = 0, total_len = 0;
+	int i, ret, total_size;
+
+	if (!q)
+		return -ENXIO;
+
+	if (!nr_srcs)
+		return -EINVAL;
+
+	if (bdev_read_only(bdev))
+		return -EPERM;
+
+	bs_mask = (bdev_logical_block_size(bdev) >> 9) - 1;
+
+	total_size = struct_size(payload, range, nr_srcs);
+	payload = kmalloc(total_size, gfp_mask);
+	if (!payload)
+		return -ENOMEM;
+
+	for (i = 0; i < nr_srcs; i++) {
+		/*  copy payload provided are in bytes */
+		src_sects = rlist[i].src;
+		if (src_sects & bs_mask) {
+			ret =  -EINVAL;
+			goto err;
+		}
+		src_sects = src_sects >> SECTOR_SHIFT;
+
+		if (len & bs_mask) {
+			ret = -EINVAL;
+			goto err;
+		}
+
+		len = rlist[i].len >> SECTOR_SHIFT;
+
+		total_len += len;
+
+		WARN_ON_ONCE((src_sects << 9) > UINT_MAX);
+
+		payload->range[i].src = src_sects;
+		payload->range[i].len = len;
+	}
+
+	/* storing # of source ranges */
+	payload->copy_range = i;
+	/* storing copy len so far */
+	payload->copy_size = total_len;
+
+	*payload_p = payload;
+	return 0;
+err:
+	kfree(payload);
+	return ret;
+}
+
+/**
+ * blkdev_issue_copy - queue a copy
+ * @bdev:       source block device
+ * @nr_srcs:	number of source ranges to copy
+ * @rlist:	array of source ranges (in bytes)
+ * @dest_bdev:	destination block device
+ * @dest:	destination (in bytes)
+ * @gfp_mask:   memory allocation flags (for bio_alloc)
+ *
+ * Description:
+ *	Copy array of source ranges from source block device to
+ *	destination block devcie.
+ */
+
+
+int blkdev_issue_copy(struct block_device *bdev, int nr_srcs,
+		struct range_entry *src_rlist, struct block_device *dest_bdev,
+		sector_t dest, gfp_t gfp_mask)
+{
+	struct request_queue *q = bdev_get_queue(bdev);
+	struct blk_copy_payload *payload;
+	sector_t bs_mask, dest_sect;
+	void *buf = NULL;
+	int ret;
+
+	ret = blk_prepare_payload(bdev, nr_srcs, src_rlist, gfp_mask, &payload);
+	if (ret)
+		return ret;
+
+	bs_mask = (bdev_logical_block_size(dest_bdev) >> 9) - 1;
+	if (dest & bs_mask) {
+		return -EINVAL;
+		goto out;
+	}
+	dest_sect = dest >> SECTOR_SHIFT;
+
+	if (bdev == dest_bdev && q->limits.copy_offload) {
+		ret = blk_copy_offload(bdev, payload, dest_sect, gfp_mask);
+		if (ret)
+			goto out;
+	} else {
+		ret = blk_read_to_buf(bdev, payload, gfp_mask, &buf);
+		if (ret)
+			goto out;
+		ret = blk_write_from_buf(dest_bdev, buf, dest_sect,
+				payload->copy_size << SECTOR_SHIFT, gfp_mask);
+	}
+
+	if (buf)
+		kvfree(buf);
+out:
+	kvfree(payload);
+	return ret;
+}
+EXPORT_SYMBOL(blkdev_issue_copy);
+
 /**
  * __blkdev_issue_write_same - generate number of bios with same page
  * @bdev:	target blockdev
diff --git a/block/blk-merge.c b/block/blk-merge.c
index 808768f6b174..4e04f24e13c1 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -309,6 +309,8 @@ void __blk_queue_split(struct bio **bio, unsigned int *nr_segs)
 	struct bio *split = NULL;
 
 	switch (bio_op(*bio)) {
+	case REQ_OP_COPY:
+			break;
 	case REQ_OP_DISCARD:
 	case REQ_OP_SECURE_ERASE:
 		split = blk_bio_discard_split(q, *bio, &q->bio_split, nr_segs);
diff --git a/block/blk-settings.c b/block/blk-settings.c
index 43990b1d148b..93c15ba45a69 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -60,6 +60,10 @@ void blk_set_default_limits(struct queue_limits *lim)
 	lim->io_opt = 0;
 	lim->misaligned = 0;
 	lim->zoned = BLK_ZONED_NONE;
+	lim->copy_offload = 0;
+	lim->max_copy_sectors = 0;
+	lim->max_copy_nr_ranges = 0;
+	lim->max_copy_range_sectors = 0;
 }
 EXPORT_SYMBOL(blk_set_default_limits);
 
@@ -565,6 +569,12 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
 	if (b->chunk_sectors)
 		t->chunk_sectors = gcd(t->chunk_sectors, b->chunk_sectors);
 
+	/* simple copy not supported in stacked devices */
+	t->copy_offload = 0;
+	t->max_copy_sectors = 0;
+	t->max_copy_range_sectors = 0;
+	t->max_copy_nr_ranges = 0;
+
 	/* Physical block size a multiple of the logical block size? */
 	if (t->physical_block_size & (t->logical_block_size - 1)) {
 		t->physical_block_size = t->logical_block_size;
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index b513f1683af0..51b35a8311d9 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -166,6 +166,47 @@ static ssize_t queue_discard_granularity_show(struct request_queue *q, char *pag
 	return queue_var_show(q->limits.discard_granularity, page);
 }
 
+static ssize_t queue_copy_offload_show(struct request_queue *q, char *page)
+{
+	return queue_var_show(q->limits.copy_offload, page);
+}
+
+static ssize_t queue_copy_offload_store(struct request_queue *q,
+				       const char *page, size_t count)
+{
+	unsigned long copy_offload;
+	ssize_t ret = queue_var_store(&copy_offload, page, count);
+
+	if (ret < 0)
+		return ret;
+
+	if (copy_offload < 0 || copy_offload > 1)
+		return -EINVAL;
+
+	if (q->limits.max_copy_sectors == 0 && copy_offload == 1)
+		return -EINVAL;
+
+	q->limits.copy_offload = copy_offload;
+	return ret;
+}
+
+static ssize_t queue_max_copy_sectors_show(struct request_queue *q, char *page)
+{
+	return queue_var_show(q->limits.max_copy_sectors, page);
+}
+
+static ssize_t queue_max_copy_range_sectors_show(struct request_queue *q,
+		char *page)
+{
+	return queue_var_show(q->limits.max_copy_range_sectors, page);
+}
+
+static ssize_t queue_max_copy_nr_ranges_show(struct request_queue *q,
+		char *page)
+{
+	return queue_var_show(q->limits.max_copy_nr_ranges, page);
+}
+
 static ssize_t queue_discard_max_hw_show(struct request_queue *q, char *page)
 {
 
@@ -591,6 +632,11 @@ QUEUE_RO_ENTRY(queue_nr_zones, "nr_zones");
 QUEUE_RO_ENTRY(queue_max_open_zones, "max_open_zones");
 QUEUE_RO_ENTRY(queue_max_active_zones, "max_active_zones");
 
+QUEUE_RW_ENTRY(queue_copy_offload, "copy_offload");
+QUEUE_RO_ENTRY(queue_max_copy_sectors, "max_copy_sectors");
+QUEUE_RO_ENTRY(queue_max_copy_range_sectors, "max_copy_range_sectors");
+QUEUE_RO_ENTRY(queue_max_copy_nr_ranges, "max_copy_nr_ranges");
+
 QUEUE_RW_ENTRY(queue_nomerges, "nomerges");
 QUEUE_RW_ENTRY(queue_rq_affinity, "rq_affinity");
 QUEUE_RW_ENTRY(queue_poll, "io_poll");
@@ -636,6 +682,10 @@ static struct attribute *queue_attrs[] = {
 	&queue_discard_max_entry.attr,
 	&queue_discard_max_hw_entry.attr,
 	&queue_discard_zeroes_data_entry.attr,
+	&queue_copy_offload_entry.attr,
+	&queue_max_copy_sectors_entry.attr,
+	&queue_max_copy_range_sectors_entry.attr,
+	&queue_max_copy_nr_ranges_entry.attr,
 	&queue_write_same_max_entry.attr,
 	&queue_write_zeroes_max_entry.attr,
 	&queue_zone_append_max_entry.attr,
diff --git a/block/blk-zoned.c b/block/blk-zoned.c
index 7a68b6e4300c..02069178d51e 100644
--- a/block/blk-zoned.c
+++ b/block/blk-zoned.c
@@ -75,6 +75,7 @@ bool blk_req_needs_zone_write_lock(struct request *rq)
 	case REQ_OP_WRITE_ZEROES:
 	case REQ_OP_WRITE_SAME:
 	case REQ_OP_WRITE:
+	case REQ_OP_COPY:
 		return blk_rq_zone_is_seq(rq);
 	default:
 		return false;
diff --git a/block/bounce.c b/block/bounce.c
index d3f51acd6e3b..5e052afe8691 100644
--- a/block/bounce.c
+++ b/block/bounce.c
@@ -254,6 +254,7 @@ static struct bio *bounce_clone_bio(struct bio *bio_src, gfp_t gfp_mask,
 	bio->bi_iter.bi_size	= bio_src->bi_iter.bi_size;
 
 	switch (bio_op(bio)) {
+	case REQ_OP_COPY:
 	case REQ_OP_DISCARD:
 	case REQ_OP_SECURE_ERASE:
 	case REQ_OP_WRITE_ZEROES:
diff --git a/block/ioctl.c b/block/ioctl.c
index d61d652078f4..d50b6abe2883 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -133,6 +133,47 @@ static int blk_ioctl_discard(struct block_device *bdev, fmode_t mode,
 				    GFP_KERNEL, flags);
 }
 
+static int blk_ioctl_copy(struct block_device *bdev, fmode_t mode,
+		unsigned long arg)
+{
+	struct copy_range crange;
+	struct range_entry *rlist;
+	struct request_queue *q = bdev_get_queue(bdev);
+	sector_t dest;
+	int ret;
+
+	if (!(mode & FMODE_WRITE))
+		return -EBADF;
+
+	if (!blk_queue_copy(q))
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&crange, (void __user *)arg, sizeof(crange)))
+		return -EFAULT;
+
+	if (crange.dest & ((1 << SECTOR_SHIFT) - 1))
+		return -EFAULT;
+	dest = crange.dest;
+
+	rlist = kmalloc_array(crange.nr_range, sizeof(*rlist),
+			GFP_KERNEL);
+
+	if (!rlist)
+		return -ENOMEM;
+
+	if (copy_from_user(rlist, (void __user *)crange.range_list,
+				sizeof(*rlist) * crange.nr_range)) {
+		ret = -EFAULT;
+		goto out;
+	}
+
+	ret = blkdev_issue_copy(bdev, crange.nr_range, rlist, bdev, dest,
+			GFP_KERNEL);
+out:
+	kfree(rlist);
+	return ret;
+}
+
 static int blk_ioctl_zeroout(struct block_device *bdev, fmode_t mode,
 		unsigned long arg)
 {
@@ -458,6 +499,8 @@ static int blkdev_common_ioctl(struct block_device *bdev, fmode_t mode,
 	case BLKSECDISCARD:
 		return blk_ioctl_discard(bdev, mode, arg,
 				BLKDEV_DISCARD_SECURE);
+	case BLKCOPY:
+		return blk_ioctl_copy(bdev, mode, arg);
 	case BLKZEROOUT:
 		return blk_ioctl_zeroout(bdev, mode, arg);
 	case BLKREPORTZONE:
diff --git a/include/linux/bio.h b/include/linux/bio.h
index 1edda614f7ce..164313bdfb35 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -71,6 +71,7 @@ static inline bool bio_has_data(struct bio *bio)
 static inline bool bio_no_advance_iter(const struct bio *bio)
 {
 	return bio_op(bio) == REQ_OP_DISCARD ||
+	       bio_op(bio) == REQ_OP_COPY ||
 	       bio_op(bio) == REQ_OP_SECURE_ERASE ||
 	       bio_op(bio) == REQ_OP_WRITE_SAME ||
 	       bio_op(bio) == REQ_OP_WRITE_ZEROES;
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index 866f74261b3b..d4d11e9ff814 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -380,6 +380,8 @@ enum req_opf {
 	REQ_OP_ZONE_RESET	= 15,
 	/* reset all the zone present on the device */
 	REQ_OP_ZONE_RESET_ALL	= 17,
+	/* copy ranges within device */
+	REQ_OP_COPY		= 19,
 
 	/* SCSI passthrough using struct scsi_request */
 	REQ_OP_SCSI_IN		= 32,
@@ -506,6 +508,11 @@ static inline bool op_is_discard(unsigned int op)
 	return (op & REQ_OP_MASK) == REQ_OP_DISCARD;
 }
 
+static inline bool op_is_copy(unsigned int op)
+{
+	return (op & REQ_OP_MASK) == REQ_OP_COPY;
+}
+
 /*
  * Check if a bio or request operation is a zone management operation, with
  * the exception of REQ_OP_ZONE_RESET_ALL which is treated as a special case
@@ -565,4 +572,12 @@ struct blk_rq_stat {
 	u64 batch;
 };
 
+struct blk_copy_payload {
+	sector_t	dest;
+	int		copy_range;
+	int		copy_size;
+	int		err;
+	struct	range_entry	range[];
+};
+
 #endif /* __LINUX_BLK_TYPES_H */
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 81f9e7bec16c..4c7e861e57e4 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -340,10 +340,14 @@ struct queue_limits {
 	unsigned int		max_zone_append_sectors;
 	unsigned int		discard_granularity;
 	unsigned int		discard_alignment;
+	unsigned int		copy_offload;
+	unsigned int		max_copy_sectors;
 
 	unsigned short		max_segments;
 	unsigned short		max_integrity_segments;
 	unsigned short		max_discard_segments;
+	unsigned short		max_copy_range_sectors;
+	unsigned short		max_copy_nr_ranges;
 
 	unsigned char		misaligned;
 	unsigned char		discard_misaligned;
@@ -625,6 +629,7 @@ struct request_queue {
 #define QUEUE_FLAG_RQ_ALLOC_TIME 27	/* record rq->alloc_time_ns */
 #define QUEUE_FLAG_HCTX_ACTIVE	28	/* at least one blk-mq hctx is active */
 #define QUEUE_FLAG_NOWAIT       29	/* device supports NOWAIT */
+#define QUEUE_FLAG_COPY		30	/* supports copy */
 
 #define QUEUE_FLAG_MQ_DEFAULT	((1 << QUEUE_FLAG_IO_STAT) |		\
 				 (1 << QUEUE_FLAG_SAME_COMP) |		\
@@ -647,6 +652,7 @@ bool blk_queue_flag_test_and_set(unsigned int flag, struct request_queue *q);
 #define blk_queue_io_stat(q)	test_bit(QUEUE_FLAG_IO_STAT, &(q)->queue_flags)
 #define blk_queue_add_random(q)	test_bit(QUEUE_FLAG_ADD_RANDOM, &(q)->queue_flags)
 #define blk_queue_discard(q)	test_bit(QUEUE_FLAG_DISCARD, &(q)->queue_flags)
+#define blk_queue_copy(q)	test_bit(QUEUE_FLAG_COPY, &(q)->queue_flags)
 #define blk_queue_zone_resetall(q)	\
 	test_bit(QUEUE_FLAG_ZONE_RESETALL, &(q)->queue_flags)
 #define blk_queue_secure_erase(q) \
@@ -1061,6 +1067,9 @@ static inline unsigned int blk_queue_get_max_sectors(struct request_queue *q,
 		return min(q->limits.max_discard_sectors,
 			   UINT_MAX >> SECTOR_SHIFT);
 
+	if (unlikely(op == REQ_OP_COPY))
+		return q->limits.max_copy_sectors;
+
 	if (unlikely(op == REQ_OP_WRITE_SAME))
 		return q->limits.max_write_same_sectors;
 
@@ -1335,6 +1344,10 @@ extern int __blkdev_issue_discard(struct block_device *bdev, sector_t sector,
 		sector_t nr_sects, gfp_t gfp_mask, int flags,
 		struct bio **biop);
 
+extern int blkdev_issue_copy(struct block_device *bdev, int nr_srcs,
+		struct range_entry *src_rlist, struct block_device *dest_bdev,
+		sector_t dest, gfp_t gfp_mask);
+
 #define BLKDEV_ZERO_NOUNMAP	(1 << 0)  /* do not free blocks */
 #define BLKDEV_ZERO_NOFALLBACK	(1 << 1)  /* don't write explicit zeroes */
 
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
index f44eb0a04afd..5cadb176317a 100644
--- a/include/uapi/linux/fs.h
+++ b/include/uapi/linux/fs.h
@@ -64,6 +64,18 @@ struct fstrim_range {
 	__u64 minlen;
 };
 
+struct range_entry {
+	__u64 src;
+	__u64 len;
+};
+
+struct copy_range {
+	__u64 dest;
+	__u64 nr_range;
+	__u64 range_list;
+	__u64 rsvd;
+};
+
 /* extent-same (dedupe) ioctls; these MUST match the btrfs ioctl definitions */
 #define FILE_DEDUPE_RANGE_SAME		0
 #define FILE_DEDUPE_RANGE_DIFFERS	1
@@ -184,6 +196,7 @@ struct fsxattr {
 #define BLKSECDISCARD _IO(0x12,125)
 #define BLKROTATIONAL _IO(0x12,126)
 #define BLKZEROOUT _IO(0x12,127)
+#define BLKCOPY _IOWR(0x12, 128, struct copy_range)
 /*
  * A jump here: 130-131 are reserved for zoned block devices
  * (see uapi/linux/blkzoned.h)
-- 
2.25.1



From selvakuma.s1 at samsung.com  Mon Jan  4 05:41:59 2021
From: selvakuma.s1 at samsung.com (SelvaKumar S)
Date: Mon,  4 Jan 2021 16:11:59 +0530
Subject: [RFC PATCH v4 3/3] nvme: add simple copy support
In-Reply-To: <20210104104159.74236-1-selvakuma.s1@samsung.com>
References: <20210104104159.74236-1-selvakuma.s1@samsung.com>
 <CGME20210104104254epcas5p212bb42457cfbaed5aeaeaa5b6625922b@epcas5p2.samsung.com>
Message-ID: <20210104104159.74236-4-selvakuma.s1@samsung.com>

Add support for  TP 4065a ("Simple Copy Command"), v2020.05.04
("Ratified")

For device supporting native simple copy, this implementation accepts
the payload passed from the block layer and convert payload to form
simple copy command and submit to the device.

Set the device copy limits to queue limits. By default copy_offload
is disabled.

End-to-end protection is done by setting both PRINFOR and PRINFOW
to 0.

Signed-off-by: SelvaKumar S <selvakuma.s1 at samsung.com>
Signed-off-by: Kanchan Joshi <joshi.k at samsung.com>
Signed-off-by: Nitesh Shetty <nj.shetty at samsung.com>
Signed-off-by: Javier Gonz?lez <javier.gonz at samsung.com>
---
 drivers/nvme/host/core.c | 87 ++++++++++++++++++++++++++++++++++++++++
 include/linux/nvme.h     | 43 ++++++++++++++++++--
 2 files changed, 127 insertions(+), 3 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index ce1b61519441..ea75af3e865a 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -708,6 +708,63 @@ static inline void nvme_setup_flush(struct nvme_ns *ns,
 	cmnd->common.nsid = cpu_to_le32(ns->head->ns_id);
 }
 
+static inline blk_status_t nvme_setup_copy(struct nvme_ns *ns,
+	       struct request *req, struct nvme_command *cmnd)
+{
+	struct nvme_ctrl *ctrl = ns->ctrl;
+	struct nvme_copy_range *range = NULL;
+	struct blk_copy_payload *payload;
+	unsigned short nr_range = 0;
+	u16 control = 0, ssrl;
+	u32 dsmgmt = 0;
+	u64 slba;
+	int i;
+
+	payload = bio_data(req->bio);
+	nr_range = payload->copy_range;
+
+	if (req->cmd_flags & REQ_FUA)
+		control |= NVME_RW_FUA;
+
+	if (req->cmd_flags & REQ_FAILFAST_DEV)
+		control |= NVME_RW_LR;
+
+	cmnd->copy.opcode = nvme_cmd_copy;
+	cmnd->copy.nsid = cpu_to_le32(ns->head->ns_id);
+	cmnd->copy.sdlba = cpu_to_le64(blk_rq_pos(req) >> (ns->lba_shift - 9));
+
+	range = kmalloc_array(nr_range, sizeof(*range),
+			GFP_ATOMIC | __GFP_NOWARN);
+	if (!range)
+		return BLK_STS_RESOURCE;
+
+	for (i = 0; i < nr_range; i++) {
+		slba = payload->range[i].src;
+		slba = slba >> (ns->lba_shift - 9);
+
+		ssrl = payload->range[i].len;
+		ssrl = ssrl >> (ns->lba_shift - 9);
+
+		range[i].slba = cpu_to_le64(slba);
+		range[i].nlb = cpu_to_le16(ssrl - 1);
+	}
+
+	cmnd->copy.nr_range = nr_range - 1;
+
+	req->special_vec.bv_page = virt_to_page(range);
+	req->special_vec.bv_offset = offset_in_page(range);
+	req->special_vec.bv_len = sizeof(*range) * nr_range;
+	req->rq_flags |= RQF_SPECIAL_PAYLOAD;
+
+	if (ctrl->nr_streams)
+		nvme_assign_write_stream(ctrl, req, &control, &dsmgmt);
+
+	cmnd->rw.control = cpu_to_le16(control);
+	cmnd->rw.dsmgmt = cpu_to_le32(dsmgmt);
+
+	return BLK_STS_OK;
+}
+
 static blk_status_t nvme_setup_discard(struct nvme_ns *ns, struct request *req,
 		struct nvme_command *cmnd)
 {
@@ -890,6 +947,9 @@ blk_status_t nvme_setup_cmd(struct nvme_ns *ns, struct request *req,
 	case REQ_OP_DISCARD:
 		ret = nvme_setup_discard(ns, req, cmd);
 		break;
+	case REQ_OP_COPY:
+		ret = nvme_setup_copy(ns, req, cmd);
+		break;
 	case REQ_OP_READ:
 		ret = nvme_setup_rw(ns, req, cmd, nvme_cmd_read);
 		break;
@@ -1917,6 +1977,31 @@ static void nvme_config_discard(struct gendisk *disk, struct nvme_ns *ns)
 		blk_queue_max_write_zeroes_sectors(queue, UINT_MAX);
 }
 
+static void nvme_config_copy(struct gendisk *disk, struct nvme_ns *ns,
+				       struct nvme_id_ns *id)
+{
+	struct nvme_ctrl *ctrl = ns->ctrl;
+	struct request_queue *queue = disk->queue;
+
+	if (!(ctrl->oncs & NVME_CTRL_ONCS_COPY)) {
+		queue->limits.copy_offload = 0;
+		queue->limits.max_copy_sectors = 0;
+		queue->limits.max_copy_range_sectors = 0;
+		queue->limits.max_copy_nr_ranges = 0;
+		blk_queue_flag_clear(QUEUE_FLAG_COPY, queue);
+		return;
+	}
+
+	/* setting copy limits */
+	blk_queue_flag_test_and_set(QUEUE_FLAG_COPY, queue);
+	queue->limits.copy_offload = 0;
+	queue->limits.max_copy_sectors = le64_to_cpu(id->mcl) *
+		(1 << (ns->lba_shift - 9));
+	queue->limits.max_copy_range_sectors = le32_to_cpu(id->mssrl) *
+		(1 << (ns->lba_shift - 9));
+	queue->limits.max_copy_nr_ranges = id->msrc + 1;
+}
+
 static void nvme_config_write_zeroes(struct gendisk *disk, struct nvme_ns *ns)
 {
 	u64 max_blocks;
@@ -2112,6 +2197,7 @@ static void nvme_update_disk_info(struct gendisk *disk,
 	set_capacity_and_notify(disk, capacity);
 
 	nvme_config_discard(disk, ns);
+	nvme_config_copy(disk, ns, id);
 	nvme_config_write_zeroes(disk, ns);
 
 	if ((id->nsattr & NVME_NS_ATTR_RO) ||
@@ -4689,6 +4775,7 @@ static inline void _nvme_check_size(void)
 	BUILD_BUG_ON(sizeof(struct nvme_download_firmware) != 64);
 	BUILD_BUG_ON(sizeof(struct nvme_format_cmd) != 64);
 	BUILD_BUG_ON(sizeof(struct nvme_dsm_cmd) != 64);
+	BUILD_BUG_ON(sizeof(struct nvme_copy_command) != 64);
 	BUILD_BUG_ON(sizeof(struct nvme_write_zeroes_cmd) != 64);
 	BUILD_BUG_ON(sizeof(struct nvme_abort_cmd) != 64);
 	BUILD_BUG_ON(sizeof(struct nvme_get_log_page_command) != 64);
diff --git a/include/linux/nvme.h b/include/linux/nvme.h
index d92535997687..11ed72a2164d 100644
--- a/include/linux/nvme.h
+++ b/include/linux/nvme.h
@@ -289,7 +289,7 @@ struct nvme_id_ctrl {
 	__u8			nvscc;
 	__u8			nwpc;
 	__le16			acwu;
-	__u8			rsvd534[2];
+	__le16			ocfs;
 	__le32			sgls;
 	__le32			mnan;
 	__u8			rsvd544[224];
@@ -314,6 +314,7 @@ enum {
 	NVME_CTRL_ONCS_WRITE_ZEROES		= 1 << 3,
 	NVME_CTRL_ONCS_RESERVATIONS		= 1 << 5,
 	NVME_CTRL_ONCS_TIMESTAMP		= 1 << 6,
+	NVME_CTRL_ONCS_COPY			= 1 << 8,
 	NVME_CTRL_VWC_PRESENT			= 1 << 0,
 	NVME_CTRL_OACS_SEC_SUPP                 = 1 << 0,
 	NVME_CTRL_OACS_DIRECTIVES		= 1 << 5,
@@ -362,7 +363,10 @@ struct nvme_id_ns {
 	__le16			npdg;
 	__le16			npda;
 	__le16			nows;
-	__u8			rsvd74[18];
+	__le16			mssrl;
+	__le32			mcl;
+	__u8			msrc;
+	__u8			rsvd91[11];
 	__le32			anagrpid;
 	__u8			rsvd96[3];
 	__u8			nsattr;
@@ -673,6 +677,7 @@ enum nvme_opcode {
 	nvme_cmd_resv_report	= 0x0e,
 	nvme_cmd_resv_acquire	= 0x11,
 	nvme_cmd_resv_release	= 0x15,
+	nvme_cmd_copy		= 0x19,
 	nvme_cmd_zone_mgmt_send	= 0x79,
 	nvme_cmd_zone_mgmt_recv	= 0x7a,
 	nvme_cmd_zone_append	= 0x7d,
@@ -691,7 +696,8 @@ enum nvme_opcode {
 		nvme_opcode_name(nvme_cmd_resv_register),	\
 		nvme_opcode_name(nvme_cmd_resv_report),		\
 		nvme_opcode_name(nvme_cmd_resv_acquire),	\
-		nvme_opcode_name(nvme_cmd_resv_release))
+		nvme_opcode_name(nvme_cmd_resv_release),	\
+		nvme_opcode_name(nvme_cmd_copy))
 
 
 /*
@@ -863,6 +869,36 @@ struct nvme_dsm_range {
 	__le64			slba;
 };
 
+struct nvme_copy_command {
+	__u8                    opcode;
+	__u8                    flags;
+	__u16                   command_id;
+	__le32                  nsid;
+	__u64                   rsvd2;
+	__le64                  metadata;
+	union nvme_data_ptr     dptr;
+	__le64                  sdlba;
+	__u8			nr_range;
+	__u8			rsvd12;
+	__le16                  control;
+	__le16                  rsvd13;
+	__le16			dspec;
+	__le32                  ilbrt;
+	__le16                  lbat;
+	__le16                  lbatm;
+};
+
+struct nvme_copy_range {
+	__le64			rsvd0;
+	__le64			slba;
+	__le16			nlb;
+	__le16			rsvd18;
+	__le32			rsvd20;
+	__le32			eilbrt;
+	__le16			elbat;
+	__le16			elbatm;
+};
+
 struct nvme_write_zeroes_cmd {
 	__u8			opcode;
 	__u8			flags;
@@ -1400,6 +1436,7 @@ struct nvme_command {
 		struct nvme_download_firmware dlfw;
 		struct nvme_format_cmd format;
 		struct nvme_dsm_cmd dsm;
+		struct nvme_copy_command copy;
 		struct nvme_write_zeroes_cmd write_zeroes;
 		struct nvme_zone_mgmt_send_cmd zms;
 		struct nvme_zone_mgmt_recv_cmd zmr;
-- 
2.25.1



From Damien.LeMoal at wdc.com  Mon Jan  4 07:15:38 2021
From: Damien.LeMoal at wdc.com (Damien Le Moal)
Date: Mon, 4 Jan 2021 12:15:38 +0000
Subject: [RFC PATCH v4 1/3] block: export bio_map_kern()
References: <20210104104159.74236-1-selvakuma.s1@samsung.com>
 <CGME20210104104245epcas5p26ed395efbf74e78a4e44048a6d7d6ba7@epcas5p2.samsung.com>
 <20210104104159.74236-2-selvakuma.s1@samsung.com>
Message-ID: <BL0PR04MB6514554D569AC302850BA1DDE7D20@BL0PR04MB6514.namprd04.prod.outlook.com>

On 2021/01/04 19:48, SelvaKumar S wrote:
> Export bio_map_kern() so that copy offload emulation can use
> it to add vmalloced memory to bio.
> 
> Signed-off-by: SelvaKumar S <selvakuma.s1 at samsung.com>
> ---
>  block/blk-map.c        | 3 ++-
>  include/linux/blkdev.h | 2 ++
>  2 files changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/block/blk-map.c b/block/blk-map.c
> index 21630dccac62..50d61475bb68 100644
> --- a/block/blk-map.c
> +++ b/block/blk-map.c
> @@ -378,7 +378,7 @@ static void bio_map_kern_endio(struct bio *bio)
>   *	Map the kernel address into a bio suitable for io to a block
>   *	device. Returns an error pointer in case of error.
>   */
> -static struct bio *bio_map_kern(struct request_queue *q, void *data,
> +struct bio *bio_map_kern(struct request_queue *q, void *data,
>  		unsigned int len, gfp_t gfp_mask)
>  {
>  	unsigned long kaddr = (unsigned long)data;
> @@ -428,6 +428,7 @@ static struct bio *bio_map_kern(struct request_queue *q, void *data,
>  	bio->bi_end_io = bio_map_kern_endio;
>  	return bio;
>  }
> +EXPORT_SYMBOL(bio_map_kern);

Simple copy support is a block layer code, so you I do not think you need this.
You only need to remove the static declaration of the function.

>  
>  static void bio_copy_kern_endio(struct bio *bio)
>  {
> diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
> index 070de09425ad..81f9e7bec16c 100644
> --- a/include/linux/blkdev.h
> +++ b/include/linux/blkdev.h
> @@ -936,6 +936,8 @@ extern int blk_rq_map_user(struct request_queue *, struct request *,
>  			   struct rq_map_data *, void __user *, unsigned long,
>  			   gfp_t);
>  extern int blk_rq_unmap_user(struct bio *);
> +extern struct bio *bio_map_kern(struct request_queue *q, void *data,
> +				unsigned int len, gfp_t gfp_mask);
>  extern int blk_rq_map_kern(struct request_queue *, struct request *, void *, unsigned int, gfp_t);
>  extern int blk_rq_map_user_iov(struct request_queue *, struct request *,
>  			       struct rq_map_data *, const struct iov_iter *,
> 


-- 
Damien Le Moal
Western Digital Research


From selvajove at gmail.com  Mon Jan  4 07:42:39 2021
From: selvajove at gmail.com (Selva Jove)
Date: Mon, 4 Jan 2021 18:12:39 +0530
Subject: [RFC PATCH v4 1/3] block: export bio_map_kern()
In-Reply-To: <BL0PR04MB6514554D569AC302850BA1DDE7D20@BL0PR04MB6514.namprd04.prod.outlook.com>
References: <20210104104159.74236-1-selvakuma.s1@samsung.com>
 <CGME20210104104245epcas5p26ed395efbf74e78a4e44048a6d7d6ba7@epcas5p2.samsung.com>
 <20210104104159.74236-2-selvakuma.s1@samsung.com>
 <BL0PR04MB6514554D569AC302850BA1DDE7D20@BL0PR04MB6514.namprd04.prod.outlook.com>
Message-ID: <CAHqX9vbuq=N0LwH25x6fHajy8Q65dyKyKJhJOksKYW1U3YGHZw@mail.gmail.com>

Thanks Damien, Will update that.

On Mon, Jan 4, 2021 at 5:45 PM Damien Le Moal <Damien.LeMoal at wdc.com> wrote:
>
> On 2021/01/04 19:48, SelvaKumar S wrote:
> > Export bio_map_kern() so that copy offload emulation can use
> > it to add vmalloced memory to bio.
> >
> > Signed-off-by: SelvaKumar S <selvakuma.s1 at samsung.com>
> > ---
> >  block/blk-map.c        | 3 ++-
> >  include/linux/blkdev.h | 2 ++
> >  2 files changed, 4 insertions(+), 1 deletion(-)
> >
> > diff --git a/block/blk-map.c b/block/blk-map.c
> > index 21630dccac62..50d61475bb68 100644
> > --- a/block/blk-map.c
> > +++ b/block/blk-map.c
> > @@ -378,7 +378,7 @@ static void bio_map_kern_endio(struct bio *bio)
> >   *   Map the kernel address into a bio suitable for io to a block
> >   *   device. Returns an error pointer in case of error.
> >   */
> > -static struct bio *bio_map_kern(struct request_queue *q, void *data,
> > +struct bio *bio_map_kern(struct request_queue *q, void *data,
> >               unsigned int len, gfp_t gfp_mask)
> >  {
> >       unsigned long kaddr = (unsigned long)data;
> > @@ -428,6 +428,7 @@ static struct bio *bio_map_kern(struct request_queue *q, void *data,
> >       bio->bi_end_io = bio_map_kern_endio;
> >       return bio;
> >  }
> > +EXPORT_SYMBOL(bio_map_kern);
>
> Simple copy support is a block layer code, so you I do not think you need this.
> You only need to remove the static declaration of the function.
>
> >
> >  static void bio_copy_kern_endio(struct bio *bio)
> >  {
> > diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
> > index 070de09425ad..81f9e7bec16c 100644
> > --- a/include/linux/blkdev.h
> > +++ b/include/linux/blkdev.h
> > @@ -936,6 +936,8 @@ extern int blk_rq_map_user(struct request_queue *, struct request *,
> >                          struct rq_map_data *, void __user *, unsigned long,
> >                          gfp_t);
> >  extern int blk_rq_unmap_user(struct bio *);
> > +extern struct bio *bio_map_kern(struct request_queue *q, void *data,
> > +                             unsigned int len, gfp_t gfp_mask);
> >  extern int blk_rq_map_kern(struct request_queue *, struct request *, void *, unsigned int, gfp_t);
> >  extern int blk_rq_map_user_iov(struct request_queue *, struct request *,
> >                              struct rq_map_data *, const struct iov_iter *,
> >
>
>
> --
> Damien Le Moal
> Western Digital Research


From Damien.LeMoal at wdc.com  Mon Jan  4 07:47:11 2021
From: Damien.LeMoal at wdc.com (Damien Le Moal)
Date: Mon, 4 Jan 2021 12:47:11 +0000
Subject: [RFC PATCH v4 2/3] block: add simple copy support
References: <20210104104159.74236-1-selvakuma.s1@samsung.com>
 <CGME20210104104249epcas5p458d1b5c39b5acfad4e7786eca5dd5c49@epcas5p4.samsung.com>
 <20210104104159.74236-3-selvakuma.s1@samsung.com>
Message-ID: <BL0PR04MB651402CFA75F72826AC8EE1CE7D20@BL0PR04MB6514.namprd04.prod.outlook.com>

On 2021/01/04 19:48, SelvaKumar S wrote:
> Add new BLKCOPY ioctl that offloads copying of one or more sources
> ranges to a destination in the device. Accepts copy_ranges that contains
> destination, no of sources and pointer to the array of source
> ranges. Each range_entry contains start and length of source
> ranges (in bytes).
> 
> Introduce REQ_OP_COPY, a no-merge copy offload operation. Create
> bio with control information as payload and submit to the device.
> REQ_OP_COPY(19) is a write op and takes zone_write_lock when submitted
> to zoned device.
> 
> If the device doesn't support copy or copy offload is disabled, then
> copy is emulated by allocating memory of total copy size. The source
> ranges are read into memory by chaining bio for each source ranges and
> submitting them async and the last bio waits for completion. After data
> is read, it is written to the destination.
> 
> bio_map_kern() is used to allocate bio and add pages of copy buffer to
> bio. As bio->bi_private and bio->bi_end_io is needed for chaining the
> bio and over written, invalidate_kernel_vmap_range() for read is called
> in the caller.
> 
> Introduce queue limits for simple copy and other helper functions.
> Add device limits as sysfs entries.
> 	- copy_offload
> 	- max_copy_sectors
> 	- max_copy_ranges_sectors
> 	- max_copy_nr_ranges
> 
> copy_offload(= 0) is disabled by default.
> max_copy_sectors = 0 indicates the device doesn't support native copy.
> 
> Native copy offload is not supported for stacked devices and is done via
> copy emulation.
> 
> Signed-off-by: SelvaKumar S <selvakuma.s1 at samsung.com>
> Signed-off-by: Kanchan Joshi <joshi.k at samsung.com>
> Signed-off-by: Nitesh Shetty <nj.shetty at samsung.com>
> Signed-off-by: Javier Gonz?lez <javier.gonz at samsung.com>
> ---
>  block/blk-core.c          |  94 ++++++++++++++--
>  block/blk-lib.c           | 223 ++++++++++++++++++++++++++++++++++++++
>  block/blk-merge.c         |   2 +
>  block/blk-settings.c      |  10 ++
>  block/blk-sysfs.c         |  50 +++++++++
>  block/blk-zoned.c         |   1 +
>  block/bounce.c            |   1 +
>  block/ioctl.c             |  43 ++++++++
>  include/linux/bio.h       |   1 +
>  include/linux/blk_types.h |  15 +++
>  include/linux/blkdev.h    |  13 +++
>  include/uapi/linux/fs.h   |  13 +++
>  12 files changed, 458 insertions(+), 8 deletions(-)
> 
> diff --git a/block/blk-core.c b/block/blk-core.c
> index 96e5fcd7f071..4a5cd3f53cd2 100644
> --- a/block/blk-core.c
> +++ b/block/blk-core.c
> @@ -719,6 +719,17 @@ static noinline int should_fail_bio(struct bio *bio)
>  }
>  ALLOW_ERROR_INJECTION(should_fail_bio, ERRNO);
>  
> +static inline int bio_check_copy_eod(struct bio *bio, sector_t start,
> +		sector_t nr_sectors, sector_t maxsector)
> +{
> +	if (nr_sectors && maxsector &&
> +	    (nr_sectors > maxsector || start > maxsector - nr_sectors)) {
> +		handle_bad_sector(bio, maxsector);
> +		return -EIO;
> +	}
> +	return 0;
> +}
> +
>  /*
>   * Check whether this bio extends beyond the end of the device or partition.
>   * This may well happen - the kernel calls bread() without checking the size of
> @@ -737,6 +748,65 @@ static inline int bio_check_eod(struct bio *bio, sector_t maxsector)
>  	return 0;
>  }
>  
> +/*
> + * Check for copy limits and remap source ranges if needed.
> + */
> +static int blk_check_copy(struct bio *bio)
> +{
> +	struct block_device *p = NULL;
> +	struct request_queue *q = bio->bi_disk->queue;
> +	struct blk_copy_payload *payload;
> +	int i, maxsector, start_sect = 0, ret = -EIO;
> +	unsigned short nr_range;
> +
> +	rcu_read_lock();
> +
> +	p = __disk_get_part(bio->bi_disk, bio->bi_partno);
> +	if (unlikely(!p))
> +		goto out;
> +	if (unlikely(should_fail_request(p, bio->bi_iter.bi_size)))
> +		goto out;
> +	if (unlikely(bio_check_ro(bio, p)))
> +		goto out;
> +
> +	maxsector =  bdev_nr_sectors(p);
> +	start_sect = p->bd_start_sect;
> +
> +	payload = bio_data(bio);
> +	nr_range = payload->copy_range;
> +
> +	/* cannot handle copy crossing nr_ranges limit */
> +	if (payload->copy_range > q->limits.max_copy_nr_ranges)
> +		goto out;

If payload->copy_range indicates the number of ranges to be copied, you should
name it payload->copy_nr_ranges.

> +
> +	/* cannot handle copy more than copy limits */

Why ? You could loop... Similarly to discard, zone reset etc.

> +	if (payload->copy_size > q->limits.max_copy_sectors)
> +		goto out;

Shouldn't the list of source ranges give the total size to be copied ?
Otherwise, if payload->copy_size is user provided, you would need to check that
the sum of the source ranges actually is equal to copy_size, no ? That means
that dropping copy_size sound like the right thing to do here.

> +
> +	/* check if copy length crosses eod */
> +	if (unlikely(bio_check_copy_eod(bio, bio->bi_iter.bi_sector,
> +					payload->copy_size, maxsector)))
> +		goto out;
> +	bio->bi_iter.bi_sector += start_sect;
> +
> +	for (i = 0; i < nr_range; i++) {
> +		if (unlikely(bio_check_copy_eod(bio, payload->range[i].src,
> +					payload->range[i].len, maxsector)))
> +			goto out;
> +
> +		/* single source range length limit */
> +		if (payload->range[i].src > q->limits.max_copy_range_sectors)
> +			goto out;
> +		payload->range[i].src += start_sect;
> +	}
> +
> +	bio->bi_partno = 0;
> +	ret = 0;
> +out:
> +	rcu_read_unlock();
> +	return ret;
> +}
> +
>  /*
>   * Remap block n of partition p to block n+start(p) of the disk.
>   */
> @@ -826,14 +896,16 @@ static noinline_for_stack bool submit_bio_checks(struct bio *bio)
>  	if (should_fail_bio(bio))
>  		goto end_io;
>  
> -	if (bio->bi_partno) {
> -		if (unlikely(blk_partition_remap(bio)))
> -			goto end_io;
> -	} else {
> -		if (unlikely(bio_check_ro(bio, bio->bi_disk->part0)))
> -			goto end_io;
> -		if (unlikely(bio_check_eod(bio, get_capacity(bio->bi_disk))))
> -			goto end_io;
> +	if (likely(!op_is_copy(bio->bi_opf))) {
> +		if (bio->bi_partno) {
> +			if (unlikely(blk_partition_remap(bio)))
> +				goto end_io;
> +		} else {
> +			if (unlikely(bio_check_ro(bio, bio->bi_disk->part0)))
> +				goto end_io;
> +			if (unlikely(bio_check_eod(bio, get_capacity(bio->bi_disk))))
> +				goto end_io;
> +		}
>  	}
>  
>  	/*
> @@ -857,6 +929,12 @@ static noinline_for_stack bool submit_bio_checks(struct bio *bio)
>  		if (!blk_queue_discard(q))
>  			goto not_supported;
>  		break;
> +	case REQ_OP_COPY:
> +		if (!blk_queue_copy(q))
> +			goto not_supported;

This check could be inside blk_check_copy(). In any case, since you added the
read-write emulation, why are you even checking this ? That will prevent the use
of the read-write emulation for devices that lack the simple copy support, no ?

> +		if (unlikely(blk_check_copy(bio)))
> +			goto end_io;
> +		break;
>  	case REQ_OP_SECURE_ERASE:
>  		if (!blk_queue_secure_erase(q))
>  			goto not_supported;
> diff --git a/block/blk-lib.c b/block/blk-lib.c
> index 752f9c722062..4c0f12e2ed7c 100644
> --- a/block/blk-lib.c
> +++ b/block/blk-lib.c
> @@ -150,6 +150,229 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
>  }
>  EXPORT_SYMBOL(blkdev_issue_discard);
>  
> +int blk_copy_offload(struct block_device *bdev, struct blk_copy_payload *payload,
> +		sector_t dest, gfp_t gfp_mask)
> +{
> +	struct bio *bio;
> +	int ret, total_size;
> +
> +	bio = bio_alloc(gfp_mask, 1);
> +	bio->bi_iter.bi_sector = dest;
> +	bio->bi_opf = REQ_OP_COPY | REQ_NOMERGE;
> +	bio_set_dev(bio, bdev);
> +
> +	total_size = struct_size(payload, range, payload->copy_range);
> +	ret = bio_add_page(bio, virt_to_page(payload), total_size,

How is payload allocated ? If it is a structure on-stack in the caller, I am not
sure it would be wise to do an IO using the thread stack page...

> +					   offset_in_page(payload));
> +	if (ret != total_size) {
> +		ret = -ENOMEM;
> +		bio_put(bio);
> +		goto err;
> +	}
> +
> +	ret = submit_bio_wait(bio);
> +err:
> +	bio_put(bio);
> +	return ret;
> +
> +}
> +
> +int blk_read_to_buf(struct block_device *bdev, struct blk_copy_payload *payload,
> +		gfp_t gfp_mask, void **buf_p)
> +{
> +	struct request_queue *q = bdev_get_queue(bdev);
> +	struct bio *bio, *parent = NULL;
> +	void *buf = NULL;
> +	bool is_vmalloc;
> +	int i, nr_srcs, copy_len, ret, cur_size, t_len = 0;
> +
> +	nr_srcs = payload->copy_range;
> +	copy_len = payload->copy_size << SECTOR_SHIFT;
> +
> +	buf = kvmalloc(copy_len, gfp_mask);
> +	if (!buf)
> +		return -ENOMEM;
> +	is_vmalloc = is_vmalloc_addr(buf);
> +
> +	for (i = 0; i < nr_srcs; i++) {
> +		cur_size = payload->range[i].len << SECTOR_SHIFT;
> +
> +		bio = bio_map_kern(q, buf + t_len, cur_size, gfp_mask);
> +		if (IS_ERR(bio)) {
> +			ret = PTR_ERR(bio);
> +			goto out;
> +		}
> +
> +		bio->bi_iter.bi_sector = payload->range[i].src;
> +		bio->bi_opf = REQ_OP_READ;
> +		bio_set_dev(bio, bdev);
> +		bio->bi_end_io = NULL;
> +		bio->bi_private = NULL;
> +
> +		if (parent) {
> +			bio_chain(parent, bio);
> +			submit_bio(parent);
> +		}
> +
> +		parent = bio;
> +		t_len += cur_size;
> +	}
> +
> +	ret = submit_bio_wait(bio);
> +	bio_put(bio);
> +	if (is_vmalloc)
> +		invalidate_kernel_vmap_range(buf, copy_len);
> +	if (ret)
> +		goto out;
> +
> +	*buf_p = buf;
> +	return 0;
> +out:
> +	kvfree(buf);
> +	return ret;
> +}
> +
> +int blk_write_from_buf(struct block_device *bdev, void *buf, sector_t dest,
> +		int copy_len, gfp_t gfp_mask)
> +{
> +	struct request_queue *q = bdev_get_queue(bdev);
> +	struct bio *bio;
> +	int ret;
> +
> +	bio = bio_map_kern(q, buf, copy_len, gfp_mask);
> +	if (IS_ERR(bio)) {
> +		ret = PTR_ERR(bio);
> +		goto out;
> +	}
> +	bio_set_dev(bio, bdev);
> +	bio->bi_opf = REQ_OP_WRITE;
> +	bio->bi_iter.bi_sector = dest;
> +
> +	bio->bi_end_io = NULL;
> +	ret = submit_bio_wait(bio);
> +	bio_put(bio);
> +out:
> +	return ret;
> +}
> +
> +int blk_prepare_payload(struct block_device *bdev, int nr_srcs, struct range_entry *rlist,
> +		gfp_t gfp_mask, struct blk_copy_payload **payload_p)
> +{
> +
> +	struct request_queue *q = bdev_get_queue(bdev);
> +	struct blk_copy_payload *payload;
> +	sector_t bs_mask;
> +	sector_t src_sects, len = 0, total_len = 0;
> +	int i, ret, total_size;
> +
> +	if (!q)
> +		return -ENXIO;
> +
> +	if (!nr_srcs)
> +		return -EINVAL;
> +
> +	if (bdev_read_only(bdev))
> +		return -EPERM;
> +
> +	bs_mask = (bdev_logical_block_size(bdev) >> 9) - 1;
> +
> +	total_size = struct_size(payload, range, nr_srcs);
> +	payload = kmalloc(total_size, gfp_mask);
> +	if (!payload)
> +		return -ENOMEM;

OK. So this is what goes into the bio. The function blk_copy_offload() assumes
this is at most one page, so total_size <= PAGE_SIZE. Where is that checked ?

> +
> +	for (i = 0; i < nr_srcs; i++) {
> +		/*  copy payload provided are in bytes */
> +		src_sects = rlist[i].src;
> +		if (src_sects & bs_mask) {
> +			ret =  -EINVAL;
> +			goto err;
> +		}
> +		src_sects = src_sects >> SECTOR_SHIFT;
> +
> +		if (len & bs_mask) {
> +			ret = -EINVAL;
> +			goto err;
> +		}
> +
> +		len = rlist[i].len >> SECTOR_SHIFT;
> +
> +		total_len += len;
> +
> +		WARN_ON_ONCE((src_sects << 9) > UINT_MAX);
> +
> +		payload->range[i].src = src_sects;
> +		payload->range[i].len = len;
> +	}
> +
> +	/* storing # of source ranges */
> +	payload->copy_range = i;
> +	/* storing copy len so far */
> +	payload->copy_size = total_len;

The comments here make the code ugly. Rename the variables and structure fields
to have something self explanatory.

> +
> +	*payload_p = payload;
> +	return 0;
> +err:
> +	kfree(payload);
> +	return ret;
> +}
> +
> +/**
> + * blkdev_issue_copy - queue a copy
> + * @bdev:       source block device
> + * @nr_srcs:	number of source ranges to copy
> + * @rlist:	array of source ranges (in bytes)
> + * @dest_bdev:	destination block device
> + * @dest:	destination (in bytes)
> + * @gfp_mask:   memory allocation flags (for bio_alloc)
> + *
> + * Description:
> + *	Copy array of source ranges from source block device to
> + *	destination block devcie.
> + */
> +
> +
> +int blkdev_issue_copy(struct block_device *bdev, int nr_srcs,
> +		struct range_entry *src_rlist, struct block_device *dest_bdev,
> +		sector_t dest, gfp_t gfp_mask)
> +{
> +	struct request_queue *q = bdev_get_queue(bdev);
> +	struct blk_copy_payload *payload;
> +	sector_t bs_mask, dest_sect;
> +	void *buf = NULL;
> +	int ret;
> +
> +	ret = blk_prepare_payload(bdev, nr_srcs, src_rlist, gfp_mask, &payload);
> +	if (ret)
> +		return ret;
> +
> +	bs_mask = (bdev_logical_block_size(dest_bdev) >> 9) - 1;
> +	if (dest & bs_mask) {
> +		return -EINVAL;
> +		goto out;
> +	}
> +	dest_sect = dest >> SECTOR_SHIFT;

dest should already be a 512B sector as all block layer functions interface use
this unit. What is this doing ?

> +
> +	if (bdev == dest_bdev && q->limits.copy_offload) {
> +		ret = blk_copy_offload(bdev, payload, dest_sect, gfp_mask);
> +		if (ret)
> +			goto out;
> +	} else {
> +		ret = blk_read_to_buf(bdev, payload, gfp_mask, &buf);
> +		if (ret)
> +			goto out;
> +		ret = blk_write_from_buf(dest_bdev, buf, dest_sect,
> +				payload->copy_size << SECTOR_SHIFT, gfp_mask);

Arg... This is really not pretty. At the very least, this should all be in a
blk_copy_emulate() helper or something named like that.

My worry though is that this likely slow for large copies, not to mention that
buf is likely to fail to allocate for large copy cases. As commented previously,
dm-kcopyd already does such copy well, with a read-write streaming pipeline and
zone support too for the write side. This should really be reused, at least
partly, instead of re-implementing this read-write here.

> +	}
> +
> +	if (buf)
> +		kvfree(buf);
> +out:
> +	kvfree(payload);
> +	return ret;
> +}
> +EXPORT_SYMBOL(blkdev_issue_copy);
> +
>  /**
>   * __blkdev_issue_write_same - generate number of bios with same page
>   * @bdev:	target blockdev
> diff --git a/block/blk-merge.c b/block/blk-merge.c
> index 808768f6b174..4e04f24e13c1 100644
> --- a/block/blk-merge.c
> +++ b/block/blk-merge.c
> @@ -309,6 +309,8 @@ void __blk_queue_split(struct bio **bio, unsigned int *nr_segs)
>  	struct bio *split = NULL;
>  
>  	switch (bio_op(*bio)) {
> +	case REQ_OP_COPY:
> +			break;
>  	case REQ_OP_DISCARD:
>  	case REQ_OP_SECURE_ERASE:
>  		split = blk_bio_discard_split(q, *bio, &q->bio_split, nr_segs);
> diff --git a/block/blk-settings.c b/block/blk-settings.c
> index 43990b1d148b..93c15ba45a69 100644
> --- a/block/blk-settings.c
> +++ b/block/blk-settings.c
> @@ -60,6 +60,10 @@ void blk_set_default_limits(struct queue_limits *lim)
>  	lim->io_opt = 0;
>  	lim->misaligned = 0;
>  	lim->zoned = BLK_ZONED_NONE;
> +	lim->copy_offload = 0;
> +	lim->max_copy_sectors = 0;
> +	lim->max_copy_nr_ranges = 0;
> +	lim->max_copy_range_sectors = 0;
>  }
>  EXPORT_SYMBOL(blk_set_default_limits);
>  
> @@ -565,6 +569,12 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
>  	if (b->chunk_sectors)
>  		t->chunk_sectors = gcd(t->chunk_sectors, b->chunk_sectors);
>  
> +	/* simple copy not supported in stacked devices */
> +	t->copy_offload = 0;
> +	t->max_copy_sectors = 0;
> +	t->max_copy_range_sectors = 0;
> +	t->max_copy_nr_ranges = 0;
> +
>  	/* Physical block size a multiple of the logical block size? */
>  	if (t->physical_block_size & (t->logical_block_size - 1)) {
>  		t->physical_block_size = t->logical_block_size;
> diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
> index b513f1683af0..51b35a8311d9 100644
> --- a/block/blk-sysfs.c
> +++ b/block/blk-sysfs.c
> @@ -166,6 +166,47 @@ static ssize_t queue_discard_granularity_show(struct request_queue *q, char *pag
>  	return queue_var_show(q->limits.discard_granularity, page);
>  }
>  
> +static ssize_t queue_copy_offload_show(struct request_queue *q, char *page)
> +{
> +	return queue_var_show(q->limits.copy_offload, page);
> +}
> +
> +static ssize_t queue_copy_offload_store(struct request_queue *q,
> +				       const char *page, size_t count)
> +{
> +	unsigned long copy_offload;
> +	ssize_t ret = queue_var_store(&copy_offload, page, count);
> +
> +	if (ret < 0)
> +		return ret;
> +
> +	if (copy_offload < 0 || copy_offload > 1)

err... "copy_offload != 1" ?

> +		return -EINVAL;
> +
> +	if (q->limits.max_copy_sectors == 0 && copy_offload == 1)
> +		return -EINVAL;
> +
> +	q->limits.copy_offload = copy_offload;
> +	return ret;
> +}
> +
> +static ssize_t queue_max_copy_sectors_show(struct request_queue *q, char *page)
> +{
> +	return queue_var_show(q->limits.max_copy_sectors, page);
> +}
> +
> +static ssize_t queue_max_copy_range_sectors_show(struct request_queue *q,
> +		char *page)
> +{
> +	return queue_var_show(q->limits.max_copy_range_sectors, page);
> +}
> +
> +static ssize_t queue_max_copy_nr_ranges_show(struct request_queue *q,
> +		char *page)
> +{
> +	return queue_var_show(q->limits.max_copy_nr_ranges, page);
> +}
> +
>  static ssize_t queue_discard_max_hw_show(struct request_queue *q, char *page)
>  {
>  
> @@ -591,6 +632,11 @@ QUEUE_RO_ENTRY(queue_nr_zones, "nr_zones");
>  QUEUE_RO_ENTRY(queue_max_open_zones, "max_open_zones");
>  QUEUE_RO_ENTRY(queue_max_active_zones, "max_active_zones");
>  
> +QUEUE_RW_ENTRY(queue_copy_offload, "copy_offload");
> +QUEUE_RO_ENTRY(queue_max_copy_sectors, "max_copy_sectors");
> +QUEUE_RO_ENTRY(queue_max_copy_range_sectors, "max_copy_range_sectors");
> +QUEUE_RO_ENTRY(queue_max_copy_nr_ranges, "max_copy_nr_ranges");
> +
>  QUEUE_RW_ENTRY(queue_nomerges, "nomerges");
>  QUEUE_RW_ENTRY(queue_rq_affinity, "rq_affinity");
>  QUEUE_RW_ENTRY(queue_poll, "io_poll");
> @@ -636,6 +682,10 @@ static struct attribute *queue_attrs[] = {
>  	&queue_discard_max_entry.attr,
>  	&queue_discard_max_hw_entry.attr,
>  	&queue_discard_zeroes_data_entry.attr,
> +	&queue_copy_offload_entry.attr,
> +	&queue_max_copy_sectors_entry.attr,
> +	&queue_max_copy_range_sectors_entry.attr,
> +	&queue_max_copy_nr_ranges_entry.attr,
>  	&queue_write_same_max_entry.attr,
>  	&queue_write_zeroes_max_entry.attr,
>  	&queue_zone_append_max_entry.attr,
> diff --git a/block/blk-zoned.c b/block/blk-zoned.c
> index 7a68b6e4300c..02069178d51e 100644
> --- a/block/blk-zoned.c
> +++ b/block/blk-zoned.c
> @@ -75,6 +75,7 @@ bool blk_req_needs_zone_write_lock(struct request *rq)
>  	case REQ_OP_WRITE_ZEROES:
>  	case REQ_OP_WRITE_SAME:
>  	case REQ_OP_WRITE:
> +	case REQ_OP_COPY:
>  		return blk_rq_zone_is_seq(rq);
>  	default:
>  		return false;
> diff --git a/block/bounce.c b/block/bounce.c
> index d3f51acd6e3b..5e052afe8691 100644
> --- a/block/bounce.c
> +++ b/block/bounce.c
> @@ -254,6 +254,7 @@ static struct bio *bounce_clone_bio(struct bio *bio_src, gfp_t gfp_mask,
>  	bio->bi_iter.bi_size	= bio_src->bi_iter.bi_size;
>  
>  	switch (bio_op(bio)) {
> +	case REQ_OP_COPY:
>  	case REQ_OP_DISCARD:
>  	case REQ_OP_SECURE_ERASE:
>  	case REQ_OP_WRITE_ZEROES:
> diff --git a/block/ioctl.c b/block/ioctl.c
> index d61d652078f4..d50b6abe2883 100644
> --- a/block/ioctl.c
> +++ b/block/ioctl.c
> @@ -133,6 +133,47 @@ static int blk_ioctl_discard(struct block_device *bdev, fmode_t mode,
>  				    GFP_KERNEL, flags);
>  }
>  
> +static int blk_ioctl_copy(struct block_device *bdev, fmode_t mode,
> +		unsigned long arg)
> +{
> +	struct copy_range crange;
> +	struct range_entry *rlist;
> +	struct request_queue *q = bdev_get_queue(bdev);
> +	sector_t dest;
> +	int ret;
> +
> +	if (!(mode & FMODE_WRITE))
> +		return -EBADF;
> +
> +	if (!blk_queue_copy(q))
> +		return -EOPNOTSUPP;

But you added the read-write emulation. So what is the point here ? This ioctl
should work for any device, with or without simple copy support. Did you test that ?

> +
> +	if (copy_from_user(&crange, (void __user *)arg, sizeof(crange)))
> +		return -EFAULT;
> +
> +	if (crange.dest & ((1 << SECTOR_SHIFT) - 1))
> +		return -EFAULT;
> +	dest = crange.dest;
> +
> +	rlist = kmalloc_array(crange.nr_range, sizeof(*rlist),
> +			GFP_KERNEL);
> +

Unnecessary blank line here.

> +	if (!rlist)
> +		return -ENOMEM;
> +
> +	if (copy_from_user(rlist, (void __user *)crange.range_list,
> +				sizeof(*rlist) * crange.nr_range)) {
> +		ret = -EFAULT;
> +		goto out;
> +	}
> +
> +	ret = blkdev_issue_copy(bdev, crange.nr_range, rlist, bdev, dest,
> +			GFP_KERNEL);
> +out:
> +	kfree(rlist);
> +	return ret;
> +}
> +
>  static int blk_ioctl_zeroout(struct block_device *bdev, fmode_t mode,
>  		unsigned long arg)
>  {
> @@ -458,6 +499,8 @@ static int blkdev_common_ioctl(struct block_device *bdev, fmode_t mode,
>  	case BLKSECDISCARD:
>  		return blk_ioctl_discard(bdev, mode, arg,
>  				BLKDEV_DISCARD_SECURE);
> +	case BLKCOPY:
> +		return blk_ioctl_copy(bdev, mode, arg);
>  	case BLKZEROOUT:
>  		return blk_ioctl_zeroout(bdev, mode, arg);
>  	case BLKREPORTZONE:
> diff --git a/include/linux/bio.h b/include/linux/bio.h
> index 1edda614f7ce..164313bdfb35 100644
> --- a/include/linux/bio.h
> +++ b/include/linux/bio.h
> @@ -71,6 +71,7 @@ static inline bool bio_has_data(struct bio *bio)
>  static inline bool bio_no_advance_iter(const struct bio *bio)
>  {
>  	return bio_op(bio) == REQ_OP_DISCARD ||
> +	       bio_op(bio) == REQ_OP_COPY ||
>  	       bio_op(bio) == REQ_OP_SECURE_ERASE ||
>  	       bio_op(bio) == REQ_OP_WRITE_SAME ||
>  	       bio_op(bio) == REQ_OP_WRITE_ZEROES;
> diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
> index 866f74261b3b..d4d11e9ff814 100644
> --- a/include/linux/blk_types.h
> +++ b/include/linux/blk_types.h
> @@ -380,6 +380,8 @@ enum req_opf {
>  	REQ_OP_ZONE_RESET	= 15,
>  	/* reset all the zone present on the device */
>  	REQ_OP_ZONE_RESET_ALL	= 17,
> +	/* copy ranges within device */
> +	REQ_OP_COPY		= 19,
>  
>  	/* SCSI passthrough using struct scsi_request */
>  	REQ_OP_SCSI_IN		= 32,
> @@ -506,6 +508,11 @@ static inline bool op_is_discard(unsigned int op)
>  	return (op & REQ_OP_MASK) == REQ_OP_DISCARD;
>  }
>  
> +static inline bool op_is_copy(unsigned int op)
> +{
> +	return (op & REQ_OP_MASK) == REQ_OP_COPY;
> +}
> +
>  /*
>   * Check if a bio or request operation is a zone management operation, with
>   * the exception of REQ_OP_ZONE_RESET_ALL which is treated as a special case
> @@ -565,4 +572,12 @@ struct blk_rq_stat {
>  	u64 batch;
>  };
>  
> +struct blk_copy_payload {
> +	sector_t	dest;
> +	int		copy_range;
> +	int		copy_size;
> +	int		err;
> +	struct	range_entry	range[];
> +};
> +
>  #endif /* __LINUX_BLK_TYPES_H */
> diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
> index 81f9e7bec16c..4c7e861e57e4 100644
> --- a/include/linux/blkdev.h
> +++ b/include/linux/blkdev.h
> @@ -340,10 +340,14 @@ struct queue_limits {
>  	unsigned int		max_zone_append_sectors;
>  	unsigned int		discard_granularity;
>  	unsigned int		discard_alignment;
> +	unsigned int		copy_offload;
> +	unsigned int		max_copy_sectors;
>  
>  	unsigned short		max_segments;
>  	unsigned short		max_integrity_segments;
>  	unsigned short		max_discard_segments;
> +	unsigned short		max_copy_range_sectors;
> +	unsigned short		max_copy_nr_ranges;
>  
>  	unsigned char		misaligned;
>  	unsigned char		discard_misaligned;
> @@ -625,6 +629,7 @@ struct request_queue {
>  #define QUEUE_FLAG_RQ_ALLOC_TIME 27	/* record rq->alloc_time_ns */
>  #define QUEUE_FLAG_HCTX_ACTIVE	28	/* at least one blk-mq hctx is active */
>  #define QUEUE_FLAG_NOWAIT       29	/* device supports NOWAIT */
> +#define QUEUE_FLAG_COPY		30	/* supports copy */

I think this should be called QUEUE_FLAG_SIMPLE_COPY to indicate more precisely
the type of copy supported. SCSI XCOPY is more advanced...

>  
>  #define QUEUE_FLAG_MQ_DEFAULT	((1 << QUEUE_FLAG_IO_STAT) |		\
>  				 (1 << QUEUE_FLAG_SAME_COMP) |		\
> @@ -647,6 +652,7 @@ bool blk_queue_flag_test_and_set(unsigned int flag, struct request_queue *q);
>  #define blk_queue_io_stat(q)	test_bit(QUEUE_FLAG_IO_STAT, &(q)->queue_flags)
>  #define blk_queue_add_random(q)	test_bit(QUEUE_FLAG_ADD_RANDOM, &(q)->queue_flags)
>  #define blk_queue_discard(q)	test_bit(QUEUE_FLAG_DISCARD, &(q)->queue_flags)
> +#define blk_queue_copy(q)	test_bit(QUEUE_FLAG_COPY, &(q)->queue_flags)
>  #define blk_queue_zone_resetall(q)	\
>  	test_bit(QUEUE_FLAG_ZONE_RESETALL, &(q)->queue_flags)
>  #define blk_queue_secure_erase(q) \
> @@ -1061,6 +1067,9 @@ static inline unsigned int blk_queue_get_max_sectors(struct request_queue *q,
>  		return min(q->limits.max_discard_sectors,
>  			   UINT_MAX >> SECTOR_SHIFT);
>  
> +	if (unlikely(op == REQ_OP_COPY))
> +		return q->limits.max_copy_sectors;
> +
>  	if (unlikely(op == REQ_OP_WRITE_SAME))
>  		return q->limits.max_write_same_sectors;
>  
> @@ -1335,6 +1344,10 @@ extern int __blkdev_issue_discard(struct block_device *bdev, sector_t sector,
>  		sector_t nr_sects, gfp_t gfp_mask, int flags,
>  		struct bio **biop);
>  
> +extern int blkdev_issue_copy(struct block_device *bdev, int nr_srcs,
> +		struct range_entry *src_rlist, struct block_device *dest_bdev,
> +		sector_t dest, gfp_t gfp_mask);
> +
>  #define BLKDEV_ZERO_NOUNMAP	(1 << 0)  /* do not free blocks */
>  #define BLKDEV_ZERO_NOFALLBACK	(1 << 1)  /* don't write explicit zeroes */
>  
> diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
> index f44eb0a04afd..5cadb176317a 100644
> --- a/include/uapi/linux/fs.h
> +++ b/include/uapi/linux/fs.h
> @@ -64,6 +64,18 @@ struct fstrim_range {
>  	__u64 minlen;
>  };
>  
> +struct range_entry {
> +	__u64 src;
> +	__u64 len;
> +};
> +
> +struct copy_range {
> +	__u64 dest;
> +	__u64 nr_range;
> +	__u64 range_list;
> +	__u64 rsvd;
> +};
> +
>  /* extent-same (dedupe) ioctls; these MUST match the btrfs ioctl definitions */
>  #define FILE_DEDUPE_RANGE_SAME		0
>  #define FILE_DEDUPE_RANGE_DIFFERS	1
> @@ -184,6 +196,7 @@ struct fsxattr {
>  #define BLKSECDISCARD _IO(0x12,125)
>  #define BLKROTATIONAL _IO(0x12,126)
>  #define BLKZEROOUT _IO(0x12,127)
> +#define BLKCOPY _IOWR(0x12, 128, struct copy_range)
>  /*
>   * A jump here: 130-131 are reserved for zoned block devices
>   * (see uapi/linux/blkzoned.h)
> 


-- 
Damien Le Moal
Western Digital Research


From mgurtovoy at nvidia.com  Mon Jan  4 07:59:47 2021
From: mgurtovoy at nvidia.com (Max Gurtovoy)
Date: Mon, 4 Jan 2021 12:59:47 +0000
Subject: [PATCH 1/1] nvme: update enumerations for status codes
Message-ID: <20210104125947.160984-1-mgurtovoy@nvidia.com>

All the updates are mentioned in the ratified NVMe 1.4 spec.

Signed-off-by: Max Gurtovoy <mgurtovoy at nvidia.com>
---
 include/linux/nvme.h | 24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/include/linux/nvme.h b/include/linux/nvme.h
index d92535997687..1c9c34be8194 100644
--- a/include/linux/nvme.h
+++ b/include/linux/nvme.h
@@ -1467,20 +1467,29 @@ enum {
 	NVME_SC_SGL_INVALID_DATA	= 0xf,
 	NVME_SC_SGL_INVALID_METADATA	= 0x10,
 	NVME_SC_SGL_INVALID_TYPE	= 0x11,
-
+	NVME_SC_CMB_INVALID_USE		= 0x12,
+	NVME_SC_PRP_INVALID_OFFSET	= 0x13,
+	NVME_SC_ATOMIC_WU_EXCEEDED	= 0x14,
+	NVME_SC_OP_DENIED		= 0x15,
 	NVME_SC_SGL_INVALID_OFFSET	= 0x16,
-	NVME_SC_SGL_INVALID_SUBTYPE	= 0x17,
-
+	NVME_SC_RESERVED		= 0x17,
+	NVME_SC_HOST_ID_INCONSIST	= 0x18,
+	NVME_SC_KA_TIMEOUT_EXPIRED	= 0x19,
+	NVME_SC_KA_TIMEOUT_INVALID	= 0x1A,
+	NVME_SC_ABORTED_PREEMPT_ABORT	= 0x1B,
 	NVME_SC_SANITIZE_FAILED		= 0x1C,
 	NVME_SC_SANITIZE_IN_PROGRESS	= 0x1D,
-
+	NVME_SC_SGL_INVALID_GRANULARITY	= 0x1E,
+	NVME_SC_CMD_NOT_SUP_CMB_QUEUE	= 0x1F,
 	NVME_SC_NS_WRITE_PROTECTED	= 0x20,
 	NVME_SC_CMD_INTERRUPTED		= 0x21,
+	NVME_SC_TRANSIENT_TR_ERR	= 0x22,
 
 	NVME_SC_LBA_RANGE		= 0x80,
 	NVME_SC_CAP_EXCEEDED		= 0x81,
 	NVME_SC_NS_NOT_READY		= 0x82,
 	NVME_SC_RESERVATION_CONFLICT	= 0x83,
+	NVME_SC_FORMAT_IN_PROGRESS	= 0x84,
 
 	/*
 	 * Command Specific Status:
@@ -1513,8 +1522,15 @@ enum {
 	NVME_SC_NS_NOT_ATTACHED		= 0x11a,
 	NVME_SC_THIN_PROV_NOT_SUPP	= 0x11b,
 	NVME_SC_CTRL_LIST_INVALID	= 0x11c,
+	NVME_SC_SELT_TEST_IN_PROGRESS	= 0x11d,
 	NVME_SC_BP_WRITE_PROHIBITED	= 0x11e,
+	NVME_SC_CTRL_ID_INVALID		= 0x11f,
+	NVME_SC_SEC_CTRL_STATE_INVALID	= 0x120,
+	NVME_SC_CTRL_RES_NUM_INVALID	= 0x121,
+	NVME_SC_RES_ID_INVALID		= 0x122,
 	NVME_SC_PMR_SAN_PROHIBITED	= 0x123,
+	NVME_SC_ANA_GROUP_ID_INVALID	= 0x124,
+	NVME_SC_ANA_ATTACH_FAILED	= 0x125,
 
 	/*
 	 * I/O Command Set Specific - NVM commands:
-- 
2.25.4



From michal.krakowiak at linux.intel.com  Mon Jan  4 10:53:43 2021
From: michal.krakowiak at linux.intel.com (Michal Krakowiak)
Date: Mon, 4 Jan 2021 16:53:43 +0100
Subject: [PATCH] nvme: trace: parse format nvm command in detail
Message-ID: <20210104155343.GA26034@michal-desk>

FTrace does not parse NVMe commands consistently. There are commands
that are being parsed in detail and commands for which the trace log
contains only raw bytes of command dwords. Add detailed parsing of
format nvm admin command to make the trace log more consistent and
human-readable.

Signed-off-by: Michal Krakowiak <michal.krakowiak at intel.com>
Acked-by: Dan Williams <dan.j.williams at intel.com>
---
 drivers/nvme/host/trace.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/drivers/nvme/host/trace.c b/drivers/nvme/host/trace.c
index 5c3cb6928f3c..e0400de713b5 100644
--- a/drivers/nvme/host/trace.c
+++ b/drivers/nvme/host/trace.c
@@ -102,6 +102,23 @@ static const char *nvme_trace_get_lba_status(struct trace_seq *p,
 	return ret;
 }

+static const char *nvme_trace_admin_format_nvm(struct trace_seq *p, u8 *cdw10)
+{
+	const char *ret = trace_seq_buffer_ptr(p);
+	u8 lbaf = cdw10[0] & 0xF;
+	u8 mset = (cdw10[0] >> 4) & 0x1;
+	u8 pi = (cdw10[0] >> 5) & 0x7;
+	u8 pil = cdw10[1] & 0x1;
+	u8 ses = (cdw10[1] >> 1) & 0x7;
+
+	trace_seq_printf(p, "lbaf=%u, mset=%u, pi=%u, pil=%u, ses=%u",
+			lbaf, mset, pi, pil, ses);
+
+	trace_seq_putc(p, 0);
+
+	return ret;
+}
+
 static const char *nvme_trace_read_write(struct trace_seq *p, u8 *cdw10)
 {
 	const char *ret = trace_seq_buffer_ptr(p);
@@ -159,6 +176,8 @@ const char *nvme_trace_parse_admin_cmd(struct trace_seq *p,
 		return nvme_trace_admin_get_features(p, cdw10);
 	case nvme_admin_get_lba_status:
 		return nvme_trace_get_lba_status(p, cdw10);
+	case nvme_admin_format_nvm:
+		return nvme_trace_admin_format_nvm(p, cdw10);
 	default:
 		return nvme_trace_common(p, cdw10);
 	}
--
2.20.1



From kbusch at kernel.org  Mon Jan  4 11:02:20 2021
From: kbusch at kernel.org (Keith Busch)
Date: Mon, 4 Jan 2021 08:02:20 -0800
Subject: [PATCH] nvme: trace: parse format nvm command in detail
In-Reply-To: <20210104155343.GA26034@michal-desk>
References: <20210104155343.GA26034@michal-desk>
Message-ID: <20210104160220.GB1024941@dhcp-10-100-145-180.wdc.com>

On Mon, Jan 04, 2021 at 04:53:43PM +0100, Michal Krakowiak wrote:
> FTrace does not parse NVMe commands consistently. There are commands
> that are being parsed in detail and commands for which the trace log
> contains only raw bytes of command dwords. Add detailed parsing of
> format nvm admin command to make the trace log more consistent and
> human-readable.

Perhaps it's too late since we've already gone done this path in the
driver, but IMO, we should have only traced raw dwords without any
additional decoding. This would have allowed consistent output for all
kernel versions and resilient to future spec changes. Then that could
have made possible for a user space utility to do the decoding to a
human friendly format, kind of like what blkparse does for block layer
trace events.


From hch at lst.de  Mon Jan  4 12:36:07 2021
From: hch at lst.de (Christoph Hellwig)
Date: Mon, 4 Jan 2021 18:36:07 +0100
Subject: [PATCH] nvme: avoid possible double fetch in handling CQE
In-Reply-To: <20201223220900.11234-1-lalithambika.krishnakumar@intel.com>
References: <20201223220900.11234-1-lalithambika.krishnakumar@intel.com>
Message-ID: <20210104173607.GA30626@lst.de>

Thanks,

applied to nvme-5.11.


From hch at lst.de  Mon Jan  4 12:36:32 2021
From: hch at lst.de (Christoph Hellwig)
Date: Mon, 4 Jan 2021 18:36:32 +0100
Subject: [PATCH V2] nvme: unexport functions with no caller
In-Reply-To: <20201230112244.10970-1-minwoo.im.dev@gmail.com>
References: <20201230112244.10970-1-minwoo.im.dev@gmail.com>
Message-ID: <20210104173632.GB30626@lst.de>

Thanks,

applied to nvme-5.11.



From kbusch at kernel.org  Mon Jan  4 13:44:35 2021
From: kbusch at kernel.org (Keith Busch)
Date: Mon, 4 Jan 2021 10:44:35 -0800
Subject: Are AER corrected errors worrying?
In-Reply-To: <20210101224028.4akud7meibjavvtf@function>
References: <20210101224028.4akud7meibjavvtf@function>
Message-ID: <20210104184435.GE1024941@dhcp-10-100-145-180.wdc.com>

On Fri, Jan 01, 2021 at 11:40:28PM +0100, Samuel Thibault wrote:
> Hello,
> 
> Our lab has bought a new Dell Latitude 5410 laptop, I installed debian
> bullseye on it with kernel 5.9.0-5-amd64, but it is spitting these
> errors now and then (sometimes a dozen per a minute):
> 
> Jan  1 23:30:53 begin kernel: [   46.675818] pcieport 0000:00:1d.0: AER: Corrected error received: 0000:02:00.0
> Jan  1 23:30:53 begin kernel: [   46.675933] nvme 0000:02:00.0: PCIe Bus Error: severity=Corrected, type=Physical Layer, (Receiver ID)
> Jan  1 23:30:53 begin kernel: [   46.676048] nvme 0000:02:00.0:   device [15b7:5006] error status/mask=00000001/0000e000
> Jan  1 23:30:53 begin kernel: [   46.676140] nvme 0000:02:00.0:    [ 0] RxErr
> 
> Since it's corrected it's not actually an issue, but how worrying is it
> to see such errors on new hardware? Documentation/PCI/pcieaer-howto.rst
> is not commenting whether we are really supposed to see some of them. I
> see forums telling to use pci=noaer to stop the error logging, but is
> that really something to do?

Additional work has to happen to correct a receiver error, so it's
possible you're getting degraded performance. You may not notice worse
performance if these are infrequent enough, though.

Sometimes these types of errors occur from low power settings, so you
can try disabling the automatic management of these (assuming the
hardware supports it). To disable nvme specific power state transitions,
the kernel parameter is "nvme_core.default_ps_max_latency_us=0". PCI
also has automatic link power savings that you can disable with
parameter "pcie_aspm=off". It might be worth seeing if either of those
changes your observation.


From darrick.wong at oracle.com  Mon Jan  4 14:02:54 2021
From: darrick.wong at oracle.com (Darrick J. Wong)
Date: Mon, 4 Jan 2021 11:02:54 -0800
Subject: [dm-devel] [RFC PATCH v4 2/3] block: add simple copy support
In-Reply-To: <BL0PR04MB651402CFA75F72826AC8EE1CE7D20@BL0PR04MB6514.namprd04.prod.outlook.com>
References: <20210104104159.74236-1-selvakuma.s1@samsung.com>
 <CGME20210104104249epcas5p458d1b5c39b5acfad4e7786eca5dd5c49@epcas5p4.samsung.com>
 <20210104104159.74236-3-selvakuma.s1@samsung.com>
 <BL0PR04MB651402CFA75F72826AC8EE1CE7D20@BL0PR04MB6514.namprd04.prod.outlook.com>
Message-ID: <20210104190254.GB6919@magnolia>

SelvaKumar S: This didn't show up on dm-devel, sorry for the OT reply...

On Mon, Jan 04, 2021 at 12:47:11PM +0000, Damien Le Moal wrote:
> On 2021/01/04 19:48, SelvaKumar S wrote:
> > Add new BLKCOPY ioctl that offloads copying of one or more sources
> > ranges to a destination in the device. Accepts copy_ranges that contains
> > destination, no of sources and pointer to the array of source
> > ranges. Each range_entry contains start and length of source
> > ranges (in bytes).
> > 
> > Introduce REQ_OP_COPY, a no-merge copy offload operation. Create
> > bio with control information as payload and submit to the device.
> > REQ_OP_COPY(19) is a write op and takes zone_write_lock when submitted
> > to zoned device.
> > 
> > If the device doesn't support copy or copy offload is disabled, then
> > copy is emulated by allocating memory of total copy size. The source
> > ranges are read into memory by chaining bio for each source ranges and
> > submitting them async and the last bio waits for completion. After data
> > is read, it is written to the destination.
> > 
> > bio_map_kern() is used to allocate bio and add pages of copy buffer to
> > bio. As bio->bi_private and bio->bi_end_io is needed for chaining the
> > bio and over written, invalidate_kernel_vmap_range() for read is called
> > in the caller.
> > 
> > Introduce queue limits for simple copy and other helper functions.
> > Add device limits as sysfs entries.
> > 	- copy_offload
> > 	- max_copy_sectors
> > 	- max_copy_ranges_sectors
> > 	- max_copy_nr_ranges
> > 
> > copy_offload(= 0) is disabled by default.
> > max_copy_sectors = 0 indicates the device doesn't support native copy.
> > 
> > Native copy offload is not supported for stacked devices and is done via
> > copy emulation.
> > 
> > Signed-off-by: SelvaKumar S <selvakuma.s1 at samsung.com>
> > Signed-off-by: Kanchan Joshi <joshi.k at samsung.com>
> > Signed-off-by: Nitesh Shetty <nj.shetty at samsung.com>
> > Signed-off-by: Javier Gonz?lez <javier.gonz at samsung.com>
> > ---
> >  block/blk-core.c          |  94 ++++++++++++++--
> >  block/blk-lib.c           | 223 ++++++++++++++++++++++++++++++++++++++
> >  block/blk-merge.c         |   2 +
> >  block/blk-settings.c      |  10 ++
> >  block/blk-sysfs.c         |  50 +++++++++
> >  block/blk-zoned.c         |   1 +
> >  block/bounce.c            |   1 +
> >  block/ioctl.c             |  43 ++++++++
> >  include/linux/bio.h       |   1 +
> >  include/linux/blk_types.h |  15 +++
> >  include/linux/blkdev.h    |  13 +++
> >  include/uapi/linux/fs.h   |  13 +++

This series should also be cc'd to linux-api since you're adding a new
userspace api.

Alternately, save yourself the trouble of passing userspace API review
by hooking this up to the existing copy_file_range call in the vfs.  /me
hopes you sent blktests to check the operation of this thing, since none
of the original patches made it to this list.

If you really /do/ need a new kernel call for this, then please send in
a manpage documenting the fields of struct range_entry and copy_range,
and how users are supposed to use this.

<now jumping to the ioctl definition because Damien already reviewed the
plumbing...>

> > diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
> > index f44eb0a04afd..5cadb176317a 100644
> > --- a/include/uapi/linux/fs.h
> > +++ b/include/uapi/linux/fs.h
> > @@ -64,6 +64,18 @@ struct fstrim_range {
> >  	__u64 minlen;
> >  };
> >  
> > +struct range_entry {
> > +	__u64 src;

Is this an offset?  Or the fd of an open bdev?

> > +	__u64 len;
> > +};
> > +
> > +struct copy_range {
> > +	__u64 dest;
> > +	__u64 nr_range;
> > +	__u64 range_list;

Hm, I think this is a pointer?  Why not just put the range_entry array
at the end of struct copy_range?

> > +	__u64 rsvd;

Also needs a flags argument so we don't have to add BLKCOPY2 in like 3
months.

--D

> > +};
> > +
> >  /* extent-same (dedupe) ioctls; these MUST match the btrfs ioctl definitions */
> >  #define FILE_DEDUPE_RANGE_SAME		0
> >  #define FILE_DEDUPE_RANGE_DIFFERS	1
> > @@ -184,6 +196,7 @@ struct fsxattr {
> >  #define BLKSECDISCARD _IO(0x12,125)
> >  #define BLKROTATIONAL _IO(0x12,126)
> >  #define BLKZEROOUT _IO(0x12,127)
> > +#define BLKCOPY _IOWR(0x12, 128, struct copy_range)
> >  /*
> >   * A jump here: 130-131 are reserved for zoned block devices
> >   * (see uapi/linux/blkzoned.h)
> > 
> 
> 
> -- 
> Damien Le Moal
> Western Digital Research
> 
> 
> 
> --
> dm-devel mailing list
> dm-devel at redhat.com
> https://www.redhat.com/mailman/listinfo/dm-devel
> 


From samuel.thibault at ens-lyon.org  Mon Jan  4 15:12:47 2021
From: samuel.thibault at ens-lyon.org (Samuel Thibault)
Date: Mon, 4 Jan 2021 21:12:47 +0100
Subject: Are AER corrected errors worrying?
In-Reply-To: <20210104184435.GE1024941@dhcp-10-100-145-180.wdc.com>
References: <20210101224028.4akud7meibjavvtf@function>
 <20210104184435.GE1024941@dhcp-10-100-145-180.wdc.com>
Message-ID: <20210104201247.5k47gueib3cw4sfr@function>

Hello,

Vidya Sagar wrote:
> Since this is a laptop, I'm suspecting that ASPM states might have
> been enabled which could be causing these errors.

Keith Busch, le lun. 04 janv. 2021 10:44:35 -0800, a ecrit:
> Sometimes these types of errors occur from low power settings, so you
> can try disabling the automatic management of these (assuming the
> hardware supports it). To disable nvme specific power state transitions,
> the kernel parameter is "nvme_core.default_ps_max_latency_us=0".

I have tried to add it, and this one line changed in lspci -vv:

02:00.0 Non-Volatile memory controller: Sandisk Corp WD Black SN750 / PC SN730 NVMe SSD (prog-if 02 [NVM Express])
[...]
	Capabilities: [c0] Express (v2) Endpoint, MSI 00                                               
[...]
		DevSta: CorrErr- NonFatalErr- FatalErr- UnsupReq- AuxPwr- TransPend-
turned to
		DevSta: CorrErr+ NonFatalErr- FatalErr- UnsupReq+ AuxPwr- TransPend-

that last value happens to be what I was seeing for that line with the
manufacturer-provided ubuntu linux kernel.

So far (30m uptime) no corrected error report, I'll watch in the coming
hours/days to see if that avoided the issue. I wasn't able to trigger
such corrected errors by loading the machine, so possibly that's indeed
the converse that I should have been trying: letting it go low power :)

> PCI also has automatic link power savings that you can disable with
> parameter "pcie_aspm=off".

I'll try that if I still see errors with the nvme_core parameter.

Samuel


From ematsumiya at suse.de  Mon Jan  4 16:06:10 2021
From: ematsumiya at suse.de (Enzo Matsumiya)
Date: Mon, 4 Jan 2021 18:06:10 -0300
Subject: [PATCH] nvme: hwmon: fix crash on device teardown
In-Reply-To: <20201230153138.4f2jd2yd2vkqndby@beryllium.lan>
References: <20201209213228.5044-1-ematsumiya@suse.de>
 <4ebb1b8c-4bb0-6ebf-3417-d4aee1bdd3a8@suse.de>
 <20201230143805.2v4izgkzbnisssvr@beryllium.lan>
 <20201230151653.ozlqlwef7f2tarwz@beryllium.lan>
 <20201230153138.4f2jd2yd2vkqndby@beryllium.lan>
Message-ID: <20210104210610.hliiupywksawgei3@hyori>

Thank you all for the feedback. I'll re-evaluate my patch and resubmit
it soon.

The problem clearly exists as I can easily reproduce it on my test
setup, but the strategy to fix it needs some rework apparently.

@Daniel maybe try tweaking your tests to use a smaller controller
loss timeout (-l option)? I do this on my tests because the default
value kicks in about 30min after hot-removal -- i.e. you
have to actually wait for the timeout to expire to trigger the bug.


Cheers,

Enzo


From samuel.thibault at ens-lyon.org  Mon Jan  4 16:36:48 2021
From: samuel.thibault at ens-lyon.org (Samuel Thibault)
Date: Mon, 4 Jan 2021 22:36:48 +0100
Subject: Are AER corrected errors worrying?
In-Reply-To: <20210104201247.5k47gueib3cw4sfr@function>
References: <20210101224028.4akud7meibjavvtf@function>
 <20210104184435.GE1024941@dhcp-10-100-145-180.wdc.com>
 <20210104201247.5k47gueib3cw4sfr@function>
Message-ID: <20210104213648.enkuq5e2o6adbiur@function>

Samuel Thibault, le lun. 04 janv. 2021 21:12:47 +0100, a ecrit:
> Vidya Sagar wrote:
> > Since this is a laptop, I'm suspecting that ASPM states might have
> > been enabled which could be causing these errors.
> 
> Keith Busch, le lun. 04 janv. 2021 10:44:35 -0800, a ecrit:
> > Sometimes these types of errors occur from low power settings, so you
> > can try disabling the automatic management of these (assuming the
> > hardware supports it). To disable nvme specific power state transitions,
> > the kernel parameter is "nvme_core.default_ps_max_latency_us=0".
> 
> I have tried to add it,
> 
> I'll watch in the coming
> hours/days to see if that avoided the issue.

I did get one

Jan  4 22:34:53 begin kernel: [ 7165.207562] pcieport 0000:00:1d.0: AER: Corrected error received: 0000:02:00.0
Jan  4 22:34:53 begin kernel: [ 7165.213891] nvme 0000:02:00.0: PCIe Bus Error: severity=Corrected, type=Physical Layer, (Receiver ID)
Jan  4 22:34:53 begin kernel: [ 7165.216949] nvme 0000:02:00.0:   device [15b7:5006] error status/mask=00000001/0000e000
Jan  4 22:34:53 begin kernel: [ 7165.219995] nvme 0000:02:00.0:    [ 0] RxErr

> > PCI also has automatic link power savings that you can disable with
> > parameter "pcie_aspm=off".
> 
> I'll try that if I still see errors with the nvme_core parameter.

I'm on it.

Samuel


From samuel.thibault at ens-lyon.org  Mon Jan  4 17:33:13 2021
From: samuel.thibault at ens-lyon.org (Samuel Thibault)
Date: Mon, 4 Jan 2021 23:33:13 +0100
Subject: Are AER corrected errors worrying?
In-Reply-To: <20210104213648.enkuq5e2o6adbiur@function>
References: <20210101224028.4akud7meibjavvtf@function>
 <20210104184435.GE1024941@dhcp-10-100-145-180.wdc.com>
 <20210104201247.5k47gueib3cw4sfr@function>
 <20210104213648.enkuq5e2o6adbiur@function>
Message-ID: <20210104223313.plaaph3erefjw3rd@function>

Samuel Thibault, le lun. 04 janv. 2021 22:36:48 +0100, a ecrit:
> Samuel Thibault, le lun. 04 janv. 2021 21:12:47 +0100, a ecrit:
> > Keith Busch, le lun. 04 janv. 2021 10:44:35 -0800, a ecrit:
> > > PCI also has automatic link power savings that you can disable with
> > > parameter "pcie_aspm=off".
> > 
> > I'll try that if I still see errors with the nvme_core parameter.
> 
> I'm on it.

(FTR It switched these lines)

02:00.0 Non-Volatile memory controller: Sandisk Corp WD Black SN750 / PC SN730 NVMe SSD (prog-if 02 [NVM Express])
	[...]
	Capabilities: [c0] Express (v2) Endpoint, MSI 00
		[...]
		DevCtl: CorrErr+ NonFatalErr+ FatalErr+ UnsupReq+
	->	DevCtl: CorrErr- NonFatalErr- FatalErr- UnsupReq-
		DevSta: CorrErr- NonFatalErr- FatalErr- UnsupReq- AuxPwr- TransPend-
	->	DevSta: CorrErr+ NonFatalErr- FatalErr- UnsupReq+ AuxPwr- TransPend-
	[...]
	Capabilities: [100 v2] Advanced Error Reporting
		CESta:  RxErr- BadTLP- BadDLLP- Rollover- Timeout- AdvNonFatalErr-
	->	CESta:  RxErr- BadTLP- BadDLLP- Rollover- Timeout- AdvNonFatalErr+
	[...]
	Capabilities: [900 v1] L1 PM Substates
		[...]
		L1SubCtl1: PCI-PM_L1.2+ PCI-PM_L1.1- ASPM_L1.2+ ASPM_L1.1-
			T_CommonMode=0us LTR1.2_Threshold=163840ns
		->	T_CommonMode=0us LTR1.2_Threshold=81920ns

Samuel


From osandov at osandov.com  Mon Jan  4 17:48:04 2021
From: osandov at osandov.com (Omar Sandoval)
Date: Mon, 4 Jan 2021 14:48:04 -0800
Subject: [PATCH V3 blktests 0/5] nvmeof-mp/srp/nvme-rdma misc fix and
 enhancement
In-Reply-To: <20201126083532.27509-1-yi.zhang@redhat.com>
References: <20201126083532.27509-1-yi.zhang@redhat.com>
Message-ID: <X/ObJB4Ixh8gplT7@relinquished.localdomain>

On Thu, Nov 26, 2020 at 04:35:27PM +0800, Yi Zhang wrote:
> Hi
> 
> This patch series addressed some failures when I run nvmeof-mp/srp
> test and also add suport to use siw for nvme-rdma/nvmeof-mp/srp  testing
> from cmdline, like this:
> 
> $ use_siw=1 nvme-trtype=rdma ./check nvme
> $ use_siw=1 ./check nvmeof-mp
> $ use_siw-1 ./check srp
> 
> V3:
> Use sed to output the scheduler from sysfs directly in patch 3
> 
> V2:
> Update the ib_srpt module path in patch 1, avoid to use ls
> Update the SKIP_REASON in patch 2
> Introduce get_scheduler_list, fix nvmeof-mp/012 and srp/012 in patch 3
> Typo fix in patch 4
> 
> Yi Zhang (5):
>   tests/srp/rc: update the ib_srpt module name
>   tests/nvmeof-mp/rc: run nvmeof-mp tests if we set multipath=N
>   nvmeof-mp/012, srp/012: fix the scheduler list
>   common/rc: _have_iproute2 fix for "ip -V" change
>   common/multipath-over-rdma: allow to set use_siw
> 
>  common/multipath-over-rdma | 13 ++++++++++++-
>  common/rc                  |  2 +-
>  tests/nvmeof-mp/012        | 10 ++++++----
>  tests/nvmeof-mp/rc         |  8 +++++---
>  tests/srp/012              | 10 ++++++----
>  tests/srp/rc               |  4 ++--
>  6 files changed, 32 insertions(+), 15 deletions(-)

Applied, thanks!


From lengchao at huawei.com  Tue Jan  5 02:19:30 2021
From: lengchao at huawei.com (Chao Leng)
Date: Tue, 5 Jan 2021 15:19:30 +0800
Subject: [PATCH 0/6] avoid repeated request completion and IO error
Message-ID: <20210105071936.25097-1-lengchao@huawei.com>

First avoid repeated request completion for nvmf_fail_nonready_command.
Second avoid IO error and repeated request completion for queue_rq.

Chao Leng (6):
  blk-mq: introduce blk_mq_set_request_complete
  nvme-core: introduce complete failed request
  nvme-fabrics: avoid repeated request completion for
    nvmf_fail_nonready_command
  nvme-rdma: avoid IO error and repeated request completion
  nvme-tcp: avoid IO error and repeated request completion
  nvme-fc: avoid IO error and repeated request completion

 drivers/nvme/host/fabrics.c |  4 +---
 drivers/nvme/host/fc.c      |  6 ++++--
 drivers/nvme/host/nvme.h    | 18 ++++++++++++++++++
 drivers/nvme/host/rdma.c    |  2 +-
 drivers/nvme/host/tcp.c     |  2 +-
 include/linux/blk-mq.h      |  5 +++++
 6 files changed, 30 insertions(+), 7 deletions(-)

-- 
2.16.4



From lengchao at huawei.com  Tue Jan  5 02:19:31 2021
From: lengchao at huawei.com (Chao Leng)
Date: Tue, 5 Jan 2021 15:19:31 +0800
Subject: [PATCH 1/6] blk-mq: introduce blk_mq_set_request_complete
In-Reply-To: <20210105071936.25097-1-lengchao@huawei.com>
References: <20210105071936.25097-1-lengchao@huawei.com>
Message-ID: <20210105071936.25097-2-lengchao@huawei.com>

In some scenarios, nvme need setting the state of request to
MQ_RQ_COMPLETE. So add an inline function blk_mq_set_request_complete.
For details, see the subsequent patches.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 include/linux/blk-mq.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h
index e7482e6ad3ec..cee72d31054d 100644
--- a/include/linux/blk-mq.h
+++ b/include/linux/blk-mq.h
@@ -493,6 +493,11 @@ static inline int blk_mq_request_completed(struct request *rq)
 	return blk_mq_rq_state(rq) == MQ_RQ_COMPLETE;
 }
 
+static inline void blk_mq_set_request_complete(struct request *rq)
+{
+	WRITE_ONCE(rq->state, MQ_RQ_COMPLETE);
+}
+
 void blk_mq_start_request(struct request *rq);
 void blk_mq_end_request(struct request *rq, blk_status_t error);
 void __blk_mq_end_request(struct request *rq, blk_status_t error);
-- 
2.16.4



From lengchao at huawei.com  Tue Jan  5 02:19:32 2021
From: lengchao at huawei.com (Chao Leng)
Date: Tue, 5 Jan 2021 15:19:32 +0800
Subject: [PATCH 2/6] nvme-core: introduce complete failed request
In-Reply-To: <20210105071936.25097-1-lengchao@huawei.com>
References: <20210105071936.25097-1-lengchao@huawei.com>
Message-ID: <20210105071936.25097-3-lengchao@huawei.com>

When a request is queued failed, if the fail status is not
BLK_STS_RESOURCE, BLK_STS_DEV_RESOURCE, BLK_STS_ZONE_RESOURCE,
the request is need to complete with nvme_complete_rq in queue_rq.
So introduce nvme_try_complete_failed_req.
The request is needed to complete with NVME_SC_HOST_PATH_ERROR in
nvmf_fail_nonready_command and queue_rq.
So introduce nvme_complete_failed_req.
For details, see the subsequent patches.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 drivers/nvme/host/nvme.h | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index bfcedfa4b057..1a0bddb9158f 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -649,6 +649,24 @@ void nvme_put_ns_from_disk(struct nvme_ns_head *head, int idx);
 extern const struct attribute_group *nvme_ns_id_attr_groups[];
 extern const struct block_device_operations nvme_ns_head_ops;
 
+static inline void nvme_complete_failed_req(struct request *req)
+{
+	nvme_req(req)->status = NVME_SC_HOST_PATH_ERROR;
+	blk_mq_set_request_complete(req);
+	nvme_complete_rq(req);
+}
+
+static inline blk_status_t nvme_try_complete_failed_req(struct request *req,
+							blk_status_t ret)
+{
+	if (ret == BLK_STS_RESOURCE || ret == BLK_STS_DEV_RESOURCE ||
+	    ret == BLK_STS_ZONE_RESOURCE)
+		return ret;
+
+	nvme_complete_failed_req(req);
+	return BLK_STS_OK;
+}
+
 #ifdef CONFIG_NVME_MULTIPATH
 static inline bool nvme_ctrl_use_ana(struct nvme_ctrl *ctrl)
 {
-- 
2.16.4



From lengchao at huawei.com  Tue Jan  5 02:19:35 2021
From: lengchao at huawei.com (Chao Leng)
Date: Tue, 5 Jan 2021 15:19:35 +0800
Subject: [PATCH 5/6] nvme-tcp: avoid IO error and repeated request completion
In-Reply-To: <20210105071936.25097-1-lengchao@huawei.com>
References: <20210105071936.25097-1-lengchao@huawei.com>
Message-ID: <20210105071936.25097-6-lengchao@huawei.com>

When a request is queued failed, blk_status_t is directly returned
to the blk-mq. If blk_status_t is not BLK_STS_RESOURCE,
BLK_STS_DEV_RESOURCE, BLK_STS_ZONE_RESOURCE, blk-mq call
blk_mq_end_request to complete the request with BLK_STS_IOERR.
In two scenarios, the request should be retried and may succeed.
First, if work with nvme multipath, the request may be retried
successfully in another path, because the error is probably related to
the path. Second, if work without multipath software, the request may
be retried successfully after error recovery.
If the request is completed with BLK_STS_IOERR in blk_mq_dispatch_rq_list.
The state of request may be changed to MQ_RQ_IN_FLIGHT. If free the
request asynchronously such as in nvme_submit_user_cmd, in extreme
scenario the request will be repeated freed in tear down.
If a non-resource error occurs when queue_rq, should directly call
nvme_complete_rq to complete request and set the state of request to
MQ_RQ_COMPLETE. nvme_complete_rq will decide to retry, fail over or end
the request.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 drivers/nvme/host/tcp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 1ba659927442..a81683ce8cff 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -2306,7 +2306,7 @@ static blk_status_t nvme_tcp_queue_rq(struct blk_mq_hw_ctx *hctx,
 
 	ret = nvme_tcp_setup_cmd_pdu(ns, rq);
 	if (unlikely(ret))
-		return ret;
+		return nvme_try_complete_failed_req(rq, ret);
 
 	blk_mq_start_request(rq);
 
-- 
2.16.4



From lengchao at huawei.com  Tue Jan  5 02:19:33 2021
From: lengchao at huawei.com (Chao Leng)
Date: Tue, 5 Jan 2021 15:19:33 +0800
Subject: [PATCH 3/6] nvme-fabrics: avoid repeated request completion for
 nvmf_fail_nonready_command
In-Reply-To: <20210105071936.25097-1-lengchao@huawei.com>
References: <20210105071936.25097-1-lengchao@huawei.com>
Message-ID: <20210105071936.25097-4-lengchao@huawei.com>

The request may be completed with NVME_SC_HOST_PATH_ERROR in
nvmf_fail_nonready_command. The state of request will be changed to
MQ_RQ_IN_FLIGHT before call nvme_complete_rq. If free the request
asynchronously such as in nvme_submit_user_cmd, in extreme scenario
the request will be repeated freed in tear down.
Nvmf_fail_nonready_command do not need calling blk_mq_start_request
before complete the request. Nvmf_fail_nonready_command should set
the state of request to MQ_RQ_COMPLETE before complete the request.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 drivers/nvme/host/fabrics.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c
index 72ac00173500..874e4320e214 100644
--- a/drivers/nvme/host/fabrics.c
+++ b/drivers/nvme/host/fabrics.c
@@ -553,9 +553,7 @@ blk_status_t nvmf_fail_nonready_command(struct nvme_ctrl *ctrl,
 	    !blk_noretry_request(rq) && !(rq->cmd_flags & REQ_NVME_MPATH))
 		return BLK_STS_RESOURCE;
 
-	nvme_req(rq)->status = NVME_SC_HOST_PATH_ERROR;
-	blk_mq_start_request(rq);
-	nvme_complete_rq(rq);
+	nvme_complete_failed_req(rq);
 	return BLK_STS_OK;
 }
 EXPORT_SYMBOL_GPL(nvmf_fail_nonready_command);
-- 
2.16.4



From lengchao at huawei.com  Tue Jan  5 02:19:36 2021
From: lengchao at huawei.com (Chao Leng)
Date: Tue, 5 Jan 2021 15:19:36 +0800
Subject: [PATCH 6/6] nvme-fc: avoid IO error and repeated request completion
In-Reply-To: <20210105071936.25097-1-lengchao@huawei.com>
References: <20210105071936.25097-1-lengchao@huawei.com>
Message-ID: <20210105071936.25097-7-lengchao@huawei.com>

When a request is queued failed, blk_status_t is directly returned
to the blk-mq. If blk_status_t is not BLK_STS_RESOURCE,
BLK_STS_DEV_RESOURCE, BLK_STS_ZONE_RESOURCE, blk-mq call
blk_mq_end_request to complete the request with BLK_STS_IOERR.
In two scenarios, the request should be retried and may succeed.
First, if work with nvme multipath, the request may be retried
successfully in another path, because the error is probably related to
the path. Second, if work without multipath software, the request may
be retried successfully after error recovery.
If the request is completed with BLK_STS_IOERR in blk_mq_dispatch_rq_list.
The state of request may be changed to MQ_RQ_IN_FLIGHT. If free the
request asynchronously such as in nvme_submit_user_cmd, in extreme
scenario the request will be repeated freed in tear down.
If a non-resource error occurs when queue_rq, should directly call
nvme_complete_rq to complete request and set the state of request to
MQ_RQ_COMPLETE. nvme_complete_rq will decide to retry, fail over or end
the request.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 drivers/nvme/host/fc.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c
index 38373a0e86ef..f6a5758ef1ea 100644
--- a/drivers/nvme/host/fc.c
+++ b/drivers/nvme/host/fc.c
@@ -2761,7 +2761,7 @@ nvme_fc_queue_rq(struct blk_mq_hw_ctx *hctx,
 
 	ret = nvme_setup_cmd(ns, rq, sqe);
 	if (ret)
-		return ret;
+		goto fail;
 
 	/*
 	 * nvme core doesn't quite treat the rq opaquely. Commands such
@@ -2781,7 +2781,9 @@ nvme_fc_queue_rq(struct blk_mq_hw_ctx *hctx,
 	}
 
 
-	return nvme_fc_start_fcp_op(ctrl, queue, op, data_len, io_dir);
+	ret = nvme_fc_start_fcp_op(ctrl, queue, op, data_len, io_dir);
+fail:
+	return nvme_try_complete_failed_req(rq, ret);
 }
 
 static void
-- 
2.16.4



From lengchao at huawei.com  Tue Jan  5 02:19:34 2021
From: lengchao at huawei.com (Chao Leng)
Date: Tue, 5 Jan 2021 15:19:34 +0800
Subject: [PATCH 4/6] nvme-rdma: avoid IO error and repeated request completion
In-Reply-To: <20210105071936.25097-1-lengchao@huawei.com>
References: <20210105071936.25097-1-lengchao@huawei.com>
Message-ID: <20210105071936.25097-5-lengchao@huawei.com>

When a request is queued failed, blk_status_t is directly returned
to the blk-mq. If blk_status_t is not BLK_STS_RESOURCE,
BLK_STS_DEV_RESOURCE, BLK_STS_ZONE_RESOURCE, blk-mq call
blk_mq_end_request to complete the request with BLK_STS_IOERR.
In two scenarios, the request should be retried and may succeed.
First, if work with nvme multipath, the request may be retried
successfully in another path, because the error is probably related to
the path. Second, if work without multipath software, the request may
be retried successfully after error recovery.
If the request is complete with BLK_STS_IOERR in blk_mq_dispatch_rq_list.
The state of request may be changed to MQ_RQ_IN_FLIGHT. If free the
request asynchronously such as in nvme_submit_user_cmd, in extreme
scenario the request will be repeated freed in tear down.
If a non-resource error occurs in queue_rq, should directly call
nvme_complete_rq to complete request and set the state of request to
MQ_RQ_COMPLETE. nvme_complete_rq will decide to retry, fail over or end
the request.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 drivers/nvme/host/rdma.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index df9f6f4549f1..4a89bf44ecdc 100644
--- a/drivers/nvme/host/rdma.c
+++ b/drivers/nvme/host/rdma.c
@@ -2093,7 +2093,7 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
 unmap_qe:
 	ib_dma_unmap_single(dev, req->sqe.dma, sizeof(struct nvme_command),
 			    DMA_TO_DEVICE);
-	return ret;
+	return nvme_try_complete_failed_req(rq, ret);
 }
 
 static int nvme_rdma_poll(struct blk_mq_hw_ctx *hctx)
-- 
2.16.4



From israelr at nvidia.com  Tue Jan  5 03:46:54 2021
From: israelr at nvidia.com (Israel Rukshin)
Date: Tue,  5 Jan 2021 10:46:54 +0200
Subject: [PATCH] nvmet-rdma: Fix list_del corruption on queue establishment
 failure
Message-ID: <1609836414-44997-1-git-send-email-israelr@nvidia.com>

When a queue is in NVMET_RDMA_Q_CONNECTING state, it may has some
requests at rsp_wait_list. In case a disconnect occurs at this
state, no one will empty this list and will return the requests to
free_rsps list. Normally nvmet_rdma_queue_established() free those
requests after moving the queue to NVMET_RDMA_Q_LIVE state, but in
this case __nvmet_rdma_queue_disconnect() is called before. The
crash happens at nvmet_rdma_free_rsps() when calling
list_del(&rsp->free_list), because the request exists only at
the wait list. To fix the issue, simply clear rsp_wait_list when
destroying the queue.

Signed-off-by: Israel Rukshin <israelr at nvidia.com>
Reviewed-by: Max Gurtovoy <mgurtovoy at nvidia.com>
---
 drivers/nvme/target/rdma.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c
index 5c1e7cb7fe0d..bdfc22eb2a10 100644
--- a/drivers/nvme/target/rdma.c
+++ b/drivers/nvme/target/rdma.c
@@ -1641,6 +1641,16 @@ static void __nvmet_rdma_queue_disconnect(struct nvmet_rdma_queue *queue)
 	spin_lock_irqsave(&queue->state_lock, flags);
 	switch (queue->state) {
 	case NVMET_RDMA_Q_CONNECTING:
+		while (!list_empty(&queue->rsp_wait_list)) {
+			struct nvmet_rdma_rsp *rsp;
+
+			rsp = list_first_entry(&queue->rsp_wait_list,
+					       struct nvmet_rdma_rsp,
+					       wait_list);
+			list_del(&rsp->wait_list);
+			nvmet_rdma_put_rsp(rsp);
+		}
+		fallthrough;
 	case NVMET_RDMA_Q_LIVE:
 		queue->state = NVMET_RDMA_Q_DISCONNECTING;
 		disconnect = true;
-- 
2.18.2



From dwagner at suse.de  Tue Jan  5 04:45:45 2021
From: dwagner at suse.de (Daniel Wagner)
Date: Tue, 5 Jan 2021 10:45:45 +0100
Subject: [PATCH] nvme: hwmon: fix crash on device teardown
In-Reply-To: <20210104210610.hliiupywksawgei3@hyori>
References: <20201209213228.5044-1-ematsumiya@suse.de>
 <4ebb1b8c-4bb0-6ebf-3417-d4aee1bdd3a8@suse.de>
 <20201230143805.2v4izgkzbnisssvr@beryllium.lan>
 <20201230151653.ozlqlwef7f2tarwz@beryllium.lan>
 <20201230153138.4f2jd2yd2vkqndby@beryllium.lan>
 <20210104210610.hliiupywksawgei3@hyori>
Message-ID: <20210105094545.3tq7c6ev5yn3bhyi@beryllium.lan>

On Mon, Jan 04, 2021 at 06:06:10PM -0300, Enzo Matsumiya wrote:
> @Daniel maybe try tweaking your tests to use a smaller controller
> loss timeout (-l option)? I do this on my tests because the default
> value kicks in about 30min after hot-removal -- i.e. you
> have to actually wait for the timeout to expire to trigger the bug.

As far I can tell, the blktests test I am using will trigger the same
bug. The problem is that the lifetime of hwmon sysfs entry should be
aligned to the lifetime of the nvme sysfs entry. Currently, hwmon's
lifetime is bound to the lifetime of the ctl sysfs entry. When the nvme
entry goes away (and obviously also the underlying device), the hwmon
sysfs entry still references it.


From mgurtovoy at nvidia.com  Tue Jan  5 05:34:02 2021
From: mgurtovoy at nvidia.com (Max Gurtovoy)
Date: Tue, 5 Jan 2021 10:34:02 +0000
Subject: [PATCH 1/1] nvme: remove the unused status argument from
 nvme_trace_bio_complete
Message-ID: <20210105103402.3121-1-mgurtovoy@nvidia.com>

The only used argument in this function is the "req".

Signed-off-by: Max Gurtovoy <mgurtovoy at nvidia.com>
---
 drivers/nvme/host/core.c | 2 +-
 drivers/nvme/host/nvme.h | 6 ++----
 2 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index ce1b61519441..7da1c42bce78 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -331,7 +331,7 @@ static inline void nvme_end_req(struct request *req)
 		req->__sector = nvme_lba_to_sect(req->q->queuedata,
 			le64_to_cpu(nvme_req(req)->result.u64));
 
-	nvme_trace_bio_complete(req, status);
+	nvme_trace_bio_complete(req);
 	blk_mq_end_request(req, status);
 }
 
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 7e49f61f81df..8bd7d8dd906c 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -675,8 +675,7 @@ static inline void nvme_mpath_check_last_path(struct nvme_ns *ns)
 		kblockd_schedule_work(&head->requeue_work);
 }
 
-static inline void nvme_trace_bio_complete(struct request *req,
-        blk_status_t status)
+static inline void nvme_trace_bio_complete(struct request *req)
 {
 	struct nvme_ns *ns = req->q->queuedata;
 
@@ -731,8 +730,7 @@ static inline void nvme_mpath_clear_ctrl_paths(struct nvme_ctrl *ctrl)
 static inline void nvme_mpath_check_last_path(struct nvme_ns *ns)
 {
 }
-static inline void nvme_trace_bio_complete(struct request *req,
-        blk_status_t status)
+static inline void nvme_trace_bio_complete(struct request *req)
 {
 }
 static inline int nvme_mpath_init(struct nvme_ctrl *ctrl,
-- 
2.25.4



From selvajove at gmail.com  Tue Jan  5 07:24:19 2021
From: selvajove at gmail.com (Selva Jove)
Date: Tue, 5 Jan 2021 17:54:19 +0530
Subject: [RFC PATCH v4 2/3] block: add simple copy support
In-Reply-To: <BL0PR04MB651402CFA75F72826AC8EE1CE7D20@BL0PR04MB6514.namprd04.prod.outlook.com>
References: <20210104104159.74236-1-selvakuma.s1@samsung.com>
 <CGME20210104104249epcas5p458d1b5c39b5acfad4e7786eca5dd5c49@epcas5p4.samsung.com>
 <20210104104159.74236-3-selvakuma.s1@samsung.com>
 <BL0PR04MB651402CFA75F72826AC8EE1CE7D20@BL0PR04MB6514.namprd04.prod.outlook.com>
Message-ID: <CAHqX9vafJ9JwkT-oDJRfbLV0WKym-6FiTQqngcP1pk8J+zgbxQ@mail.gmail.com>

Thanks for the review, Damien.

On Mon, Jan 4, 2021 at 6:17 PM Damien Le Moal <Damien.LeMoal at wdc.com> wrote:
>
> On 2021/01/04 19:48, SelvaKumar S wrote:
> > Add new BLKCOPY ioctl that offloads copying of one or more sources
> > ranges to a destination in the device. Accepts copy_ranges that contains
> > destination, no of sources and pointer to the array of source
> > ranges. Each range_entry contains start and length of source
> > ranges (in bytes).
> >
> > Introduce REQ_OP_COPY, a no-merge copy offload operation. Create
> > bio with control information as payload and submit to the device.
> > REQ_OP_COPY(19) is a write op and takes zone_write_lock when submitted
> > to zoned device.
> >
> > If the device doesn't support copy or copy offload is disabled, then
> > copy is emulated by allocating memory of total copy size. The source
> > ranges are read into memory by chaining bio for each source ranges and
> > submitting them async and the last bio waits for completion. After data
> > is read, it is written to the destination.
> >
> > bio_map_kern() is used to allocate bio and add pages of copy buffer to
> > bio. As bio->bi_private and bio->bi_end_io is needed for chaining the
> > bio and over written, invalidate_kernel_vmap_range() for read is called
> > in the caller.
> >
> > Introduce queue limits for simple copy and other helper functions.
> > Add device limits as sysfs entries.
> >       - copy_offload
> >       - max_copy_sectors
> >       - max_copy_ranges_sectors
> >       - max_copy_nr_ranges
> >
> > copy_offload(= 0) is disabled by default.
> > max_copy_sectors = 0 indicates the device doesn't support native copy.
> >
> > Native copy offload is not supported for stacked devices and is done via
> > copy emulation.
> >
> > Signed-off-by: SelvaKumar S <selvakuma.s1 at samsung.com>
> > Signed-off-by: Kanchan Joshi <joshi.k at samsung.com>
> > Signed-off-by: Nitesh Shetty <nj.shetty at samsung.com>
> > Signed-off-by: Javier Gonz?lez <javier.gonz at samsung.com>
> > ---
> >  block/blk-core.c          |  94 ++++++++++++++--
> >  block/blk-lib.c           | 223 ++++++++++++++++++++++++++++++++++++++
> >  block/blk-merge.c         |   2 +
> >  block/blk-settings.c      |  10 ++
> >  block/blk-sysfs.c         |  50 +++++++++
> >  block/blk-zoned.c         |   1 +
> >  block/bounce.c            |   1 +
> >  block/ioctl.c             |  43 ++++++++
> >  include/linux/bio.h       |   1 +
> >  include/linux/blk_types.h |  15 +++
> >  include/linux/blkdev.h    |  13 +++
> >  include/uapi/linux/fs.h   |  13 +++
> >  12 files changed, 458 insertions(+), 8 deletions(-)
> >
> > diff --git a/block/blk-core.c b/block/blk-core.c
> > index 96e5fcd7f071..4a5cd3f53cd2 100644
> > --- a/block/blk-core.c
> > +++ b/block/blk-core.c
> > @@ -719,6 +719,17 @@ static noinline int should_fail_bio(struct bio *bio)
> >  }
> >  ALLOW_ERROR_INJECTION(should_fail_bio, ERRNO);
> >
> > +static inline int bio_check_copy_eod(struct bio *bio, sector_t start,
> > +             sector_t nr_sectors, sector_t maxsector)
> > +{
> > +     if (nr_sectors && maxsector &&
> > +         (nr_sectors > maxsector || start > maxsector - nr_sectors)) {
> > +             handle_bad_sector(bio, maxsector);
> > +             return -EIO;
> > +     }
> > +     return 0;
> > +}
> > +
> >  /*
> >   * Check whether this bio extends beyond the end of the device or partition.
> >   * This may well happen - the kernel calls bread() without checking the size of
> > @@ -737,6 +748,65 @@ static inline int bio_check_eod(struct bio *bio, sector_t maxsector)
> >       return 0;
> >  }
> >
> > +/*
> > + * Check for copy limits and remap source ranges if needed.
> > + */
> > +static int blk_check_copy(struct bio *bio)
> > +{
> > +     struct block_device *p = NULL;
> > +     struct request_queue *q = bio->bi_disk->queue;
> > +     struct blk_copy_payload *payload;
> > +     int i, maxsector, start_sect = 0, ret = -EIO;
> > +     unsigned short nr_range;
> > +
> > +     rcu_read_lock();
> > +
> > +     p = __disk_get_part(bio->bi_disk, bio->bi_partno);
> > +     if (unlikely(!p))
> > +             goto out;
> > +     if (unlikely(should_fail_request(p, bio->bi_iter.bi_size)))
> > +             goto out;
> > +     if (unlikely(bio_check_ro(bio, p)))
> > +             goto out;
> > +
> > +     maxsector =  bdev_nr_sectors(p);
> > +     start_sect = p->bd_start_sect;
> > +
> > +     payload = bio_data(bio);
> > +     nr_range = payload->copy_range;
> > +
> > +     /* cannot handle copy crossing nr_ranges limit */
> > +     if (payload->copy_range > q->limits.max_copy_nr_ranges)
> > +             goto out;
>
> If payload->copy_range indicates the number of ranges to be copied, you should
> name it payload->copy_nr_ranges.
>

Agreed. Will rename the entries.

> > +
> > +     /* cannot handle copy more than copy limits */
>
> Why ? You could loop... Similarly to discard, zone reset etc.
>

Sure. Will add the support for handling copy larger than device limits.

>
> > +     if (payload->copy_size > q->limits.max_copy_sectors)
> > +             goto out;
>
> Shouldn't the list of source ranges give the total size to be copied ?
> Otherwise, if payload->copy_size is user provided, you would need to check that
> the sum of the source ranges actually is equal to copy_size, no ? That means
> that dropping copy_size sound like the right thing to do here.
>

payload->copy_size is used in copy emulation to allocate the buffer.
Let me check
one more time if it is possible to do without this.

> > +
> > +     /* check if copy length crosses eod */
> > +     if (unlikely(bio_check_copy_eod(bio, bio->bi_iter.bi_sector,
> > +                                     payload->copy_size, maxsector)))
> > +             goto out;
> > +     bio->bi_iter.bi_sector += start_sect;
> > +
> > +     for (i = 0; i < nr_range; i++) {
> > +             if (unlikely(bio_check_copy_eod(bio, payload->range[i].src,
> > +                                     payload->range[i].len, maxsector)))
> > +                     goto out;
> > +
> > +             /* single source range length limit */
> > +             if (payload->range[i].src > q->limits.max_copy_range_sectors)
> > +                     goto out;
> > +             payload->range[i].src += start_sect;
> > +     }
> > +
> > +     bio->bi_partno = 0;
> > +     ret = 0;
> > +out:
> > +     rcu_read_unlock();
> > +     return ret;
> > +}
> > +
> >  /*
> >   * Remap block n of partition p to block n+start(p) of the disk.
> >   */
> > @@ -826,14 +896,16 @@ static noinline_for_stack bool submit_bio_checks(struct bio *bio)
> >       if (should_fail_bio(bio))
> >               goto end_io;
> >
> > -     if (bio->bi_partno) {
> > -             if (unlikely(blk_partition_remap(bio)))
> > -                     goto end_io;
> > -     } else {
> > -             if (unlikely(bio_check_ro(bio, bio->bi_disk->part0)))
> > -                     goto end_io;
> > -             if (unlikely(bio_check_eod(bio, get_capacity(bio->bi_disk))))
> > -                     goto end_io;
> > +     if (likely(!op_is_copy(bio->bi_opf))) {
> > +             if (bio->bi_partno) {
> > +                     if (unlikely(blk_partition_remap(bio)))
> > +                             goto end_io;
> > +             } else {
> > +                     if (unlikely(bio_check_ro(bio, bio->bi_disk->part0)))
> > +                             goto end_io;
> > +                     if (unlikely(bio_check_eod(bio, get_capacity(bio->bi_disk))))
> > +                             goto end_io;
> > +             }
> >       }
> >
> >       /*
> > @@ -857,6 +929,12 @@ static noinline_for_stack bool submit_bio_checks(struct bio *bio)
> >               if (!blk_queue_discard(q))
> >                       goto not_supported;
> >               break;
> > +     case REQ_OP_COPY:
> > +             if (!blk_queue_copy(q))
> > +                     goto not_supported;
>
> This check could be inside blk_check_copy(). In any case, since you added the
> read-write emulation, why are you even checking this ? That will prevent the use
> of the read-write emulation for devices that lack the simple copy support, no ?
>

Makes sense. Will remove this check.

>
> > +             if (unlikely(blk_check_copy(bio)))
> > +                     goto end_io;
> > +             break;
> >       case REQ_OP_SECURE_ERASE:
> >               if (!blk_queue_secure_erase(q))
> >                       goto not_supported;
> > diff --git a/block/blk-lib.c b/block/blk-lib.c
> > index 752f9c722062..4c0f12e2ed7c 100644
> > --- a/block/blk-lib.c
> > +++ b/block/blk-lib.c
> > @@ -150,6 +150,229 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
> >  }
> >  EXPORT_SYMBOL(blkdev_issue_discard);
> >
> > +int blk_copy_offload(struct block_device *bdev, struct blk_copy_payload *payload,
> > +             sector_t dest, gfp_t gfp_mask)
> > +{
> > +     struct bio *bio;
> > +     int ret, total_size;
> > +
> > +     bio = bio_alloc(gfp_mask, 1);
> > +     bio->bi_iter.bi_sector = dest;
> > +     bio->bi_opf = REQ_OP_COPY | REQ_NOMERGE;
> > +     bio_set_dev(bio, bdev);
> > +
> > +     total_size = struct_size(payload, range, payload->copy_range);
> > +     ret = bio_add_page(bio, virt_to_page(payload), total_size,
>
> How is payload allocated ? If it is a structure on-stack in the caller, I am not
> sure it would be wise to do an IO using the thread stack page...
>
> > +                                        offset_in_page(payload));
> > +     if (ret != total_size) {
> > +             ret = -ENOMEM;
> > +             bio_put(bio);
> > +             goto err;
> > +     }
> > +
> > +     ret = submit_bio_wait(bio);
> > +err:
> > +     bio_put(bio);
> > +     return ret;
> > +
> > +}
> > +
> > +int blk_read_to_buf(struct block_device *bdev, struct blk_copy_payload *payload,
> > +             gfp_t gfp_mask, void **buf_p)
> > +{
> > +     struct request_queue *q = bdev_get_queue(bdev);
> > +     struct bio *bio, *parent = NULL;
> > +     void *buf = NULL;
> > +     bool is_vmalloc;
> > +     int i, nr_srcs, copy_len, ret, cur_size, t_len = 0;
> > +
> > +     nr_srcs = payload->copy_range;
> > +     copy_len = payload->copy_size << SECTOR_SHIFT;
> > +
> > +     buf = kvmalloc(copy_len, gfp_mask);
> > +     if (!buf)
> > +             return -ENOMEM;
> > +     is_vmalloc = is_vmalloc_addr(buf);
> > +
> > +     for (i = 0; i < nr_srcs; i++) {
> > +             cur_size = payload->range[i].len << SECTOR_SHIFT;
> > +
> > +             bio = bio_map_kern(q, buf + t_len, cur_size, gfp_mask);
> > +             if (IS_ERR(bio)) {
> > +                     ret = PTR_ERR(bio);
> > +                     goto out;
> > +             }
> > +
> > +             bio->bi_iter.bi_sector = payload->range[i].src;
> > +             bio->bi_opf = REQ_OP_READ;
> > +             bio_set_dev(bio, bdev);
> > +             bio->bi_end_io = NULL;
> > +             bio->bi_private = NULL;
> > +
> > +             if (parent) {
> > +                     bio_chain(parent, bio);
> > +                     submit_bio(parent);
> > +             }
> > +
> > +             parent = bio;
> > +             t_len += cur_size;
> > +     }
> > +
> > +     ret = submit_bio_wait(bio);
> > +     bio_put(bio);
> > +     if (is_vmalloc)
> > +             invalidate_kernel_vmap_range(buf, copy_len);
> > +     if (ret)
> > +             goto out;
> > +
> > +     *buf_p = buf;
> > +     return 0;
> > +out:
> > +     kvfree(buf);
> > +     return ret;
> > +}
> > +
> > +int blk_write_from_buf(struct block_device *bdev, void *buf, sector_t dest,
> > +             int copy_len, gfp_t gfp_mask)
> > +{
> > +     struct request_queue *q = bdev_get_queue(bdev);
> > +     struct bio *bio;
> > +     int ret;
> > +
> > +     bio = bio_map_kern(q, buf, copy_len, gfp_mask);
> > +     if (IS_ERR(bio)) {
> > +             ret = PTR_ERR(bio);
> > +             goto out;
> > +     }
> > +     bio_set_dev(bio, bdev);
> > +     bio->bi_opf = REQ_OP_WRITE;
> > +     bio->bi_iter.bi_sector = dest;
> > +
> > +     bio->bi_end_io = NULL;
> > +     ret = submit_bio_wait(bio);
> > +     bio_put(bio);
> > +out:
> > +     return ret;
> > +}
> > +
> > +int blk_prepare_payload(struct block_device *bdev, int nr_srcs, struct range_entry *rlist,
> > +             gfp_t gfp_mask, struct blk_copy_payload **payload_p)
> > +{
> > +
> > +     struct request_queue *q = bdev_get_queue(bdev);
> > +     struct blk_copy_payload *payload;
> > +     sector_t bs_mask;
> > +     sector_t src_sects, len = 0, total_len = 0;
> > +     int i, ret, total_size;
> > +
> > +     if (!q)
> > +             return -ENXIO;
> > +
> > +     if (!nr_srcs)
> > +             return -EINVAL;
> > +
> > +     if (bdev_read_only(bdev))
> > +             return -EPERM;
> > +
> > +     bs_mask = (bdev_logical_block_size(bdev) >> 9) - 1;
> > +
> > +     total_size = struct_size(payload, range, nr_srcs);
> > +     payload = kmalloc(total_size, gfp_mask);
> > +     if (!payload)
> > +             return -ENOMEM;
>
> OK. So this is what goes into the bio. The function blk_copy_offload() assumes
> this is at most one page, so total_size <= PAGE_SIZE. Where is that checked ?
>

CMIIW. As payload was allocated via kmalloc, it would be represented by a single
contiguous segment. In case it crosses one page, rely on multi-page bio_vec to
cover it.

> > +
> > +     for (i = 0; i < nr_srcs; i++) {
> > +             /*  copy payload provided are in bytes */
> > +             src_sects = rlist[i].src;
> > +             if (src_sects & bs_mask) {
> > +                     ret =  -EINVAL;
> > +                     goto err;
> > +             }
> > +             src_sects = src_sects >> SECTOR_SHIFT;
> > +
> > +             if (len & bs_mask) {
> > +                     ret = -EINVAL;
> > +                     goto err;
> > +             }
> > +
> > +             len = rlist[i].len >> SECTOR_SHIFT;
> > +
> > +             total_len += len;
> > +
> > +             WARN_ON_ONCE((src_sects << 9) > UINT_MAX);
> > +
> > +             payload->range[i].src = src_sects;
> > +             payload->range[i].len = len;
> > +     }
> > +
> > +     /* storing # of source ranges */
> > +     payload->copy_range = i;
> > +     /* storing copy len so far */
> > +     payload->copy_size = total_len;
>
> The comments here make the code ugly. Rename the variables and structure fields
> to have something self explanatory.
>

Agreed.

> > +
> > +     *payload_p = payload;
> > +     return 0;
> > +err:
> > +     kfree(payload);
> > +     return ret;
> > +}
> > +
> > +/**
> > + * blkdev_issue_copy - queue a copy
> > + * @bdev:       source block device
> > + * @nr_srcs: number of source ranges to copy
> > + * @rlist:   array of source ranges (in bytes)
> > + * @dest_bdev:       destination block device
> > + * @dest:    destination (in bytes)
> > + * @gfp_mask:   memory allocation flags (for bio_alloc)
> > + *
> > + * Description:
> > + *   Copy array of source ranges from source block device to
> > + *   destination block devcie.
> > + */
> > +
> > +
> > +int blkdev_issue_copy(struct block_device *bdev, int nr_srcs,
> > +             struct range_entry *src_rlist, struct block_device *dest_bdev,
> > +             sector_t dest, gfp_t gfp_mask)
> > +{
> > +     struct request_queue *q = bdev_get_queue(bdev);
> > +     struct blk_copy_payload *payload;
> > +     sector_t bs_mask, dest_sect;
> > +     void *buf = NULL;
> > +     int ret;
> > +
> > +     ret = blk_prepare_payload(bdev, nr_srcs, src_rlist, gfp_mask, &payload);
> > +     if (ret)
> > +             return ret;
> > +
> > +     bs_mask = (bdev_logical_block_size(dest_bdev) >> 9) - 1;
> > +     if (dest & bs_mask) {
> > +             return -EINVAL;
> > +             goto out;
> > +     }
> > +     dest_sect = dest >> SECTOR_SHIFT;
>
> dest should already be a 512B sector as all block layer functions interface use
> this unit. What is this doing ?
>

As source ranges and length received were in bytes, to keep things
same, dest was
also chosen to be in bytes. Seems wrong. Will change it to the 512B sector.

>
> > +
> > +     if (bdev == dest_bdev && q->limits.copy_offload) {
> > +             ret = blk_copy_offload(bdev, payload, dest_sect, gfp_mask);
> > +             if (ret)
> > +                     goto out;
> > +     } else {
> > +             ret = blk_read_to_buf(bdev, payload, gfp_mask, &buf);
> > +             if (ret)
> > +                     goto out;
> > +             ret = blk_write_from_buf(dest_bdev, buf, dest_sect,
> > +                             payload->copy_size << SECTOR_SHIFT, gfp_mask);
>
> Arg... This is really not pretty. At the very least, this should all be in a
> blk_copy_emulate() helper or something named like that.
>

Okay. Will move this to a helper.

> My worry though is that this likely slow for large copies, not to mention that
> buf is likely to fail to allocate for large copy cases. As commented previously,
> dm-kcopyd already does such copy well, with a read-write streaming pipeline and
> zone support too for the write side. This should really be reused, at least
> partly, instead of re-implementing this read-write here.
>

I was a bit hesitant to use dm layer code in the block layer. It makes sense to
reuse the code as much as possible. Will try to reuse dm-kcopyd code for copy
emulation part.

>
> > +     }
> > +
> > +     if (buf)
> > +             kvfree(buf);
> > +out:
> > +     kvfree(payload);
> > +     return ret;
> > +}
> > +EXPORT_SYMBOL(blkdev_issue_copy);
> > +
> >  /**
> >   * __blkdev_issue_write_same - generate number of bios with same page
> >   * @bdev:    target blockdev
> > diff --git a/block/blk-merge.c b/block/blk-merge.c
> > index 808768f6b174..4e04f24e13c1 100644
> > --- a/block/blk-merge.c
> > +++ b/block/blk-merge.c
> > @@ -309,6 +309,8 @@ void __blk_queue_split(struct bio **bio, unsigned int *nr_segs)
> >       struct bio *split = NULL;
> >
> >       switch (bio_op(*bio)) {
> > +     case REQ_OP_COPY:
> > +                     break;
> >       case REQ_OP_DISCARD:
> >       case REQ_OP_SECURE_ERASE:
> >               split = blk_bio_discard_split(q, *bio, &q->bio_split, nr_segs);
> > diff --git a/block/blk-settings.c b/block/blk-settings.c
> > index 43990b1d148b..93c15ba45a69 100644
> > --- a/block/blk-settings.c
> > +++ b/block/blk-settings.c
> > @@ -60,6 +60,10 @@ void blk_set_default_limits(struct queue_limits *lim)
> >       lim->io_opt = 0;
> >       lim->misaligned = 0;
> >       lim->zoned = BLK_ZONED_NONE;
> > +     lim->copy_offload = 0;
> > +     lim->max_copy_sectors = 0;
> > +     lim->max_copy_nr_ranges = 0;
> > +     lim->max_copy_range_sectors = 0;
> >  }
> >  EXPORT_SYMBOL(blk_set_default_limits);
> >
> > @@ -565,6 +569,12 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
> >       if (b->chunk_sectors)
> >               t->chunk_sectors = gcd(t->chunk_sectors, b->chunk_sectors);
> >
> > +     /* simple copy not supported in stacked devices */
> > +     t->copy_offload = 0;
> > +     t->max_copy_sectors = 0;
> > +     t->max_copy_range_sectors = 0;
> > +     t->max_copy_nr_ranges = 0;
> > +
> >       /* Physical block size a multiple of the logical block size? */
> >       if (t->physical_block_size & (t->logical_block_size - 1)) {
> >               t->physical_block_size = t->logical_block_size;
> > diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
> > index b513f1683af0..51b35a8311d9 100644
> > --- a/block/blk-sysfs.c
> > +++ b/block/blk-sysfs.c
> > @@ -166,6 +166,47 @@ static ssize_t queue_discard_granularity_show(struct request_queue *q, char *pag
> >       return queue_var_show(q->limits.discard_granularity, page);
> >  }
> >
> > +static ssize_t queue_copy_offload_show(struct request_queue *q, char *page)
> > +{
> > +     return queue_var_show(q->limits.copy_offload, page);
> > +}
> > +
> > +static ssize_t queue_copy_offload_store(struct request_queue *q,
> > +                                    const char *page, size_t count)
> > +{
> > +     unsigned long copy_offload;
> > +     ssize_t ret = queue_var_store(&copy_offload, page, count);
> > +
> > +     if (ret < 0)
> > +             return ret;
> > +
> > +     if (copy_offload < 0 || copy_offload > 1)
>
> err... "copy_offload != 1" ?

Initial thought was to keep it either 0 or 1.  I'll change it to 0 or else.

>
> > +             return -EINVAL;
> > +
> > +     if (q->limits.max_copy_sectors == 0 && copy_offload == 1)
> > +             return -EINVAL;
> > +
> > +     q->limits.copy_offload = copy_offload;
> > +     return ret;
> > +}
> > +
> > +static ssize_t queue_max_copy_sectors_show(struct request_queue *q, char *page)
> > +{
> > +     return queue_var_show(q->limits.max_copy_sectors, page);
> > +}
> > +
> > +static ssize_t queue_max_copy_range_sectors_show(struct request_queue *q,
> > +             char *page)
> > +{
> > +     return queue_var_show(q->limits.max_copy_range_sectors, page);
> > +}
> > +
> > +static ssize_t queue_max_copy_nr_ranges_show(struct request_queue *q,
> > +             char *page)
> > +{
> > +     return queue_var_show(q->limits.max_copy_nr_ranges, page);
> > +}
> > +
> >  static ssize_t queue_discard_max_hw_show(struct request_queue *q, char *page)
> >  {
> >
> > @@ -591,6 +632,11 @@ QUEUE_RO_ENTRY(queue_nr_zones, "nr_zones");
> >  QUEUE_RO_ENTRY(queue_max_open_zones, "max_open_zones");
> >  QUEUE_RO_ENTRY(queue_max_active_zones, "max_active_zones");
> >
> > +QUEUE_RW_ENTRY(queue_copy_offload, "copy_offload");
> > +QUEUE_RO_ENTRY(queue_max_copy_sectors, "max_copy_sectors");
> > +QUEUE_RO_ENTRY(queue_max_copy_range_sectors, "max_copy_range_sectors");
> > +QUEUE_RO_ENTRY(queue_max_copy_nr_ranges, "max_copy_nr_ranges");
> > +
> >  QUEUE_RW_ENTRY(queue_nomerges, "nomerges");
> >  QUEUE_RW_ENTRY(queue_rq_affinity, "rq_affinity");
> >  QUEUE_RW_ENTRY(queue_poll, "io_poll");
> > @@ -636,6 +682,10 @@ static struct attribute *queue_attrs[] = {
> >       &queue_discard_max_entry.attr,
> >       &queue_discard_max_hw_entry.attr,
> >       &queue_discard_zeroes_data_entry.attr,
> > +     &queue_copy_offload_entry.attr,
> > +     &queue_max_copy_sectors_entry.attr,
> > +     &queue_max_copy_range_sectors_entry.attr,
> > +     &queue_max_copy_nr_ranges_entry.attr,
> >       &queue_write_same_max_entry.attr,
> >       &queue_write_zeroes_max_entry.attr,
> >       &queue_zone_append_max_entry.attr,
> > diff --git a/block/blk-zoned.c b/block/blk-zoned.c
> > index 7a68b6e4300c..02069178d51e 100644
> > --- a/block/blk-zoned.c
> > +++ b/block/blk-zoned.c
> > @@ -75,6 +75,7 @@ bool blk_req_needs_zone_write_lock(struct request *rq)
> >       case REQ_OP_WRITE_ZEROES:
> >       case REQ_OP_WRITE_SAME:
> >       case REQ_OP_WRITE:
> > +     case REQ_OP_COPY:
> >               return blk_rq_zone_is_seq(rq);
> >       default:
> >               return false;
> > diff --git a/block/bounce.c b/block/bounce.c
> > index d3f51acd6e3b..5e052afe8691 100644
> > --- a/block/bounce.c
> > +++ b/block/bounce.c
> > @@ -254,6 +254,7 @@ static struct bio *bounce_clone_bio(struct bio *bio_src, gfp_t gfp_mask,
> >       bio->bi_iter.bi_size    = bio_src->bi_iter.bi_size;
> >
> >       switch (bio_op(bio)) {
> > +     case REQ_OP_COPY:
> >       case REQ_OP_DISCARD:
> >       case REQ_OP_SECURE_ERASE:
> >       case REQ_OP_WRITE_ZEROES:
> > diff --git a/block/ioctl.c b/block/ioctl.c
> > index d61d652078f4..d50b6abe2883 100644
> > --- a/block/ioctl.c
> > +++ b/block/ioctl.c
> > @@ -133,6 +133,47 @@ static int blk_ioctl_discard(struct block_device *bdev, fmode_t mode,
> >                                   GFP_KERNEL, flags);
> >  }
> >
> > +static int blk_ioctl_copy(struct block_device *bdev, fmode_t mode,
> > +             unsigned long arg)
> > +{
> > +     struct copy_range crange;
> > +     struct range_entry *rlist;
> > +     struct request_queue *q = bdev_get_queue(bdev);
> > +     sector_t dest;
> > +     int ret;
> > +
> > +     if (!(mode & FMODE_WRITE))
> > +             return -EBADF;
> > +
> > +     if (!blk_queue_copy(q))
> > +             return -EOPNOTSUPP;
>
> But you added the read-write emulation. So what is the point here ? This ioctl
> should work for any device, with or without simple copy support. Did you test that ?
>

Sorry. It was a mistake. Will fix this.

> > +
> > +     if (copy_from_user(&crange, (void __user *)arg, sizeof(crange)))
> > +             return -EFAULT;
> > +
> > +     if (crange.dest & ((1 << SECTOR_SHIFT) - 1))
> > +             return -EFAULT;
> > +     dest = crange.dest;
> > +
> > +     rlist = kmalloc_array(crange.nr_range, sizeof(*rlist),
> > +                     GFP_KERNEL);
> > +
>
> Unnecessary blank line here.
>
> > +     if (!rlist)
> > +             return -ENOMEM;
> > +
> > +     if (copy_from_user(rlist, (void __user *)crange.range_list,
> > +                             sizeof(*rlist) * crange.nr_range)) {
> > +             ret = -EFAULT;
> > +             goto out;
> > +     }
> > +
> > +     ret = blkdev_issue_copy(bdev, crange.nr_range, rlist, bdev, dest,
> > +                     GFP_KERNEL);
> > +out:
> > +     kfree(rlist);
> > +     return ret;
> > +}
> > +
> >  static int blk_ioctl_zeroout(struct block_device *bdev, fmode_t mode,
> >               unsigned long arg)
> >  {
> > @@ -458,6 +499,8 @@ static int blkdev_common_ioctl(struct block_device *bdev, fmode_t mode,
> >       case BLKSECDISCARD:
> >               return blk_ioctl_discard(bdev, mode, arg,
> >                               BLKDEV_DISCARD_SECURE);
> > +     case BLKCOPY:
> > +             return blk_ioctl_copy(bdev, mode, arg);
> >       case BLKZEROOUT:
> >               return blk_ioctl_zeroout(bdev, mode, arg);
> >       case BLKREPORTZONE:
> > diff --git a/include/linux/bio.h b/include/linux/bio.h
> > index 1edda614f7ce..164313bdfb35 100644
> > --- a/include/linux/bio.h
> > +++ b/include/linux/bio.h
> > @@ -71,6 +71,7 @@ static inline bool bio_has_data(struct bio *bio)
> >  static inline bool bio_no_advance_iter(const struct bio *bio)
> >  {
> >       return bio_op(bio) == REQ_OP_DISCARD ||
> > +            bio_op(bio) == REQ_OP_COPY ||
> >              bio_op(bio) == REQ_OP_SECURE_ERASE ||
> >              bio_op(bio) == REQ_OP_WRITE_SAME ||
> >              bio_op(bio) == REQ_OP_WRITE_ZEROES;
> > diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
> > index 866f74261b3b..d4d11e9ff814 100644
> > --- a/include/linux/blk_types.h
> > +++ b/include/linux/blk_types.h
> > @@ -380,6 +380,8 @@ enum req_opf {
> >       REQ_OP_ZONE_RESET       = 15,
> >       /* reset all the zone present on the device */
> >       REQ_OP_ZONE_RESET_ALL   = 17,
> > +     /* copy ranges within device */
> > +     REQ_OP_COPY             = 19,
> >
> >       /* SCSI passthrough using struct scsi_request */
> >       REQ_OP_SCSI_IN          = 32,
> > @@ -506,6 +508,11 @@ static inline bool op_is_discard(unsigned int op)
> >       return (op & REQ_OP_MASK) == REQ_OP_DISCARD;
> >  }
> >
> > +static inline bool op_is_copy(unsigned int op)
> > +{
> > +     return (op & REQ_OP_MASK) == REQ_OP_COPY;
> > +}
> > +
> >  /*
> >   * Check if a bio or request operation is a zone management operation, with
> >   * the exception of REQ_OP_ZONE_RESET_ALL which is treated as a special case
> > @@ -565,4 +572,12 @@ struct blk_rq_stat {
> >       u64 batch;
> >  };
> >
> > +struct blk_copy_payload {
> > +     sector_t        dest;
> > +     int             copy_range;
> > +     int             copy_size;
> > +     int             err;
> > +     struct  range_entry     range[];
> > +};
> > +
> >  #endif /* __LINUX_BLK_TYPES_H */
> > diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
> > index 81f9e7bec16c..4c7e861e57e4 100644
> > --- a/include/linux/blkdev.h
> > +++ b/include/linux/blkdev.h
> > @@ -340,10 +340,14 @@ struct queue_limits {
> >       unsigned int            max_zone_append_sectors;
> >       unsigned int            discard_granularity;
> >       unsigned int            discard_alignment;
> > +     unsigned int            copy_offload;
> > +     unsigned int            max_copy_sectors;
> >
> >       unsigned short          max_segments;
> >       unsigned short          max_integrity_segments;
> >       unsigned short          max_discard_segments;
> > +     unsigned short          max_copy_range_sectors;
> > +     unsigned short          max_copy_nr_ranges;
> >
> >       unsigned char           misaligned;
> >       unsigned char           discard_misaligned;
> > @@ -625,6 +629,7 @@ struct request_queue {
> >  #define QUEUE_FLAG_RQ_ALLOC_TIME 27  /* record rq->alloc_time_ns */
> >  #define QUEUE_FLAG_HCTX_ACTIVE       28      /* at least one blk-mq hctx is active */
> >  #define QUEUE_FLAG_NOWAIT       29   /* device supports NOWAIT */
> > +#define QUEUE_FLAG_COPY              30      /* supports copy */
>
> I think this should be called QUEUE_FLAG_SIMPLE_COPY to indicate more precisely
> the type of copy supported. SCSI XCOPY is more advanced...
>

Agreed.

> >
> >  #define QUEUE_FLAG_MQ_DEFAULT        ((1 << QUEUE_FLAG_IO_STAT) |            \
> >                                (1 << QUEUE_FLAG_SAME_COMP) |          \
> > @@ -647,6 +652,7 @@ bool blk_queue_flag_test_and_set(unsigned int flag, struct request_queue *q);
> >  #define blk_queue_io_stat(q) test_bit(QUEUE_FLAG_IO_STAT, &(q)->queue_flags)
> >  #define blk_queue_add_random(q)      test_bit(QUEUE_FLAG_ADD_RANDOM, &(q)->queue_flags)
> >  #define blk_queue_discard(q) test_bit(QUEUE_FLAG_DISCARD, &(q)->queue_flags)
> > +#define blk_queue_copy(q)    test_bit(QUEUE_FLAG_COPY, &(q)->queue_flags)
> >  #define blk_queue_zone_resetall(q)   \
> >       test_bit(QUEUE_FLAG_ZONE_RESETALL, &(q)->queue_flags)
> >  #define blk_queue_secure_erase(q) \
> > @@ -1061,6 +1067,9 @@ static inline unsigned int blk_queue_get_max_sectors(struct request_queue *q,
> >               return min(q->limits.max_discard_sectors,
> >                          UINT_MAX >> SECTOR_SHIFT);
> >
> > +     if (unlikely(op == REQ_OP_COPY))
> > +             return q->limits.max_copy_sectors;
> > +
> >       if (unlikely(op == REQ_OP_WRITE_SAME))
> >               return q->limits.max_write_same_sectors;
> >
> > @@ -1335,6 +1344,10 @@ extern int __blkdev_issue_discard(struct block_device *bdev, sector_t sector,
> >               sector_t nr_sects, gfp_t gfp_mask, int flags,
> >               struct bio **biop);
> >
> > +extern int blkdev_issue_copy(struct block_device *bdev, int nr_srcs,
> > +             struct range_entry *src_rlist, struct block_device *dest_bdev,
> > +             sector_t dest, gfp_t gfp_mask);
> > +
> >  #define BLKDEV_ZERO_NOUNMAP  (1 << 0)  /* do not free blocks */
> >  #define BLKDEV_ZERO_NOFALLBACK       (1 << 1)  /* don't write explicit zeroes */
> >
> > diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
> > index f44eb0a04afd..5cadb176317a 100644
> > --- a/include/uapi/linux/fs.h
> > +++ b/include/uapi/linux/fs.h
> > @@ -64,6 +64,18 @@ struct fstrim_range {
> >       __u64 minlen;
> >  };
> >
> > +struct range_entry {
> > +     __u64 src;
> > +     __u64 len;
> > +};
> > +
> > +struct copy_range {
> > +     __u64 dest;
> > +     __u64 nr_range;
> > +     __u64 range_list;
> > +     __u64 rsvd;
> > +};
> > +
> >  /* extent-same (dedupe) ioctls; these MUST match the btrfs ioctl definitions */
> >  #define FILE_DEDUPE_RANGE_SAME               0
> >  #define FILE_DEDUPE_RANGE_DIFFERS    1
> > @@ -184,6 +196,7 @@ struct fsxattr {
> >  #define BLKSECDISCARD _IO(0x12,125)
> >  #define BLKROTATIONAL _IO(0x12,126)
> >  #define BLKZEROOUT _IO(0x12,127)
> > +#define BLKCOPY _IOWR(0x12, 128, struct copy_range)
> >  /*
> >   * A jump here: 130-131 are reserved for zoned block devices
> >   * (see uapi/linux/blkzoned.h)
> >
>
>
> --
> Damien Le Moal
> Western Digital Research

Thanks,
Selva


From minwoo.im.dev at gmail.com  Tue Jan  5 07:27:16 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Tue,  5 Jan 2021 21:27:16 +0900
Subject: [PATCH V4 0/1] block: fix I/O errors in BLKRRPART
Message-ID: <20210105122717.2568-1-minwoo.im.dev@gmail.com>

Hello,

  This patch fixes I/O errors during BLKRRPART ioctl() behavior right
after format operation that changed logical block size of the block
device with a same file descriptor opened.

Testcase:

  The following testcase is a case of NVMe namespace with the following
conditions:

  - Current LBA format is lbaf=0 (512 bytes logical block size)
  - LBA Format(lbaf=1) has 4096 bytes logical block size

  # Format block device logical block size 512B to 4096B                                                                                                                                                                                                                                                                                                                                       
  nvme format /dev/nvme0n1 --lbaf=1 --force

  This will cause I/O errors because BLKRRPART ioctl() happened right after
the format command with same file descriptor opened in application
(e.g., nvme-cli) like:

  fd = open("/dev/nvme0n1", O_RDONLY);

  nvme_format(fd, ...);
  if (ioctl(fd, BLKRRPART) < 0)
        ...

Errors:

  We can see the Read command with Number of LBA(NLB) 0xffff(65535) which
was under-flowed because BLKRRPART operation requested request size based
on i_blkbits of the block device which is 9 via buffer_head.

  [dmesg-snip]
    [   10.771740] blk_update_request: operation not supported error, dev nvme0n1, sector 0 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 0
    [   10.780262] Buffer I/O error on dev nvme0n1, logical block 0, async page read

  [event-snip]
    kworker/0:1H-56      [000] ....   913.456922: nvme_setup_cmd: nvme0: disk=nvme0n1, qid=1, cmdid=216, nsid=1, flags=0x0, meta=0x0, cmd=(nvme_cmd_read slba=0, len=65535, ctrl=0x0, dsmgmt=0, reftag=0)
     ksoftirqd/0-9       [000] .Ns.   916.566351: nvme_complete_rq: nvme0: disk=nvme0n1, qid=1, cmdid=216, res=0x0, retries=0, flags=0x0, status=0x4002

  The patch below fixes the I/O errors by rejecting I/O requests from the
block layer with setting a flag to request_queue until the file descriptor
re-opened to be updated by __blkdev_get().  This is based on the previous
discussion [1].

Since V3(RFC):
  - Move flag from gendisk to request_queue for future clean-ups.
    (Christoph, [3])

Since V2(RFC):
  - Cover letter with testcase and error logs attached. Removed un-related
    changes: empty line. (Chaitanya, [2])
  - Put blkdev with blkdev_put_no_open().

Since V1(RFC):
  - Updated patch to reject I/O rather than updating i_blkbits of the
    block device's inode directly from driver. (Christoph, [1])

[1] https://lore.kernel.org/linux-nvme/20201223183143.GB13354 at localhost.localdomain/T/#t
[2] https://lore.kernel.org/linux-nvme/20201230140504.GB7917 at localhost.localdomain/T/#t
[3] https://lore.kernel.org/linux-block/20210105101202.GA9970 at localhost.localdomain/T/#u

Thanks,

Minwoo Im (1):
  block: reject I/O for same fd if block size changed

 block/blk-settings.c    |  3 +++
 block/partitions/core.c | 12 ++++++++++++
 fs/block_dev.c          |  8 ++++++++
 include/linux/blkdev.h  |  1 +
 4 files changed, 24 insertions(+)

-- 
2.17.1



From minwoo.im.dev at gmail.com  Tue Jan  5 07:27:17 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Tue,  5 Jan 2021 21:27:17 +0900
Subject: [PATCH V4 1/1] block: reject I/O for same fd if block size changed
In-Reply-To: <20210105122717.2568-1-minwoo.im.dev@gmail.com>
References: <20210105122717.2568-1-minwoo.im.dev@gmail.com>
Message-ID: <20210105122717.2568-2-minwoo.im.dev@gmail.com>

This patch fixes I/O errors during BLKRRPART ioctl() behavior right
after format operation that changed logical block size of the block
device with a same file descriptor opened.

This issue can be easily reproduced with a single format command in case
of NVMe (logical block size 512B to 4096B).

	nvme format /dev/nvme0n1 --lbaf=1 --force

This is because the application, nvme-cli format subcommand issues an
admin command followed by BLKRRPART ioctl to re-read partition
information without closing the file descriptor.  If file descriptor
stays opened, __blkdev_get() will not be invoked at all even logical
block size has been changed.

It will cause I/O errors with invalid Read operations during the
BLKRRPART ioctl due to i_blkbits mismatch. The invalid operations in
BLKRRPART happens with under-flowed Number of LBA(NLB) values
0xffff(65535) because i_blkbits is still set to 9 even the logical block
size has been updated to 4096.  The BLKRRPART will lead buffer_head to
hold 512B data which is less than the logical lock size of the block
device.

The root cause, which is because i_blkbits of inode of the block device
is not updated, can be solved easily by re-opening file descriptor
again from application.  But, that's just for application's business
and kernel should reject invalid Read operations during the BLKRRPART
ioctl.

This patch rejects I/O from the path of add_partitions() to avoid
issuing invalid Read operations to device.  It sets a flag to
request_queue in blk_queue_logical_block_size to minimize caller-side
updates.

Signed-off-by: Minwoo Im <minwoo.im.dev at gmail.com>
---
 block/blk-settings.c    |  3 +++
 block/partitions/core.c | 12 ++++++++++++
 fs/block_dev.c          |  8 ++++++++
 include/linux/blkdev.h  |  1 +
 4 files changed, 24 insertions(+)

diff --git a/block/blk-settings.c b/block/blk-settings.c
index 43990b1d148b..48a6fc7bb5f5 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -329,6 +329,9 @@ void blk_queue_logical_block_size(struct request_queue *q, unsigned int size)
 {
 	struct queue_limits *limits = &q->limits;
 
+	if (limits->logical_block_size != size)
+		blk_queue_flag_set(QUEUE_FLAG_LBSZ_CHANGED, q);
+
 	limits->logical_block_size = size;
 
 	if (limits->physical_block_size < size)
diff --git a/block/partitions/core.c b/block/partitions/core.c
index e7d776db803b..6f175ea18ff3 100644
--- a/block/partitions/core.c
+++ b/block/partitions/core.c
@@ -612,12 +612,24 @@ static bool blk_add_partition(struct gendisk *disk, struct block_device *bdev,
 
 int blk_add_partitions(struct gendisk *disk, struct block_device *bdev)
 {
+	struct request_queue *q = bdev_get_queue(bdev);
 	struct parsed_partitions *state;
 	int ret = -EAGAIN, p, highest;
 
 	if (!disk_part_scan_enabled(disk))
 		return 0;
 
+	/*
+	 * Reject to check partition information if block size has been changed
+	 * in the runtime.  If block size of a block device has been changed,
+	 * the file descriptor should be opened agian to update the blkbits.
+	 */
+	if (test_bit(QUEUE_FLAG_LBSZ_CHANGED, &q->queue_flags)) {
+		pr_warn("%s: rejecting checking partition. fd should be opened again.\n",
+				disk->disk_name);
+		return -EBADFD;
+	}
+
 	state = check_partition(disk, bdev);
 	if (!state)
 		return 0;
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 9293045e128c..8056a412a3d1 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -130,7 +130,15 @@ EXPORT_SYMBOL(truncate_bdev_range);
 
 static void set_init_blocksize(struct block_device *bdev)
 {
+	struct request_queue *q = bdev_get_queue(bdev);
+
 	bdev->bd_inode->i_blkbits = blksize_bits(bdev_logical_block_size(bdev));
+
+	/*
+	 * Allow I/O commands for this block device.  We can say that this
+	 * block device has proper blkbits updated.
+	 */
+	blk_queue_flag_clear(QUEUE_FLAG_LBSZ_CHANGED, q);
 }
 
 int set_blocksize(struct block_device *bdev, int size)
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 070de09425ad..6d0542434be6 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -625,6 +625,7 @@ struct request_queue {
 #define QUEUE_FLAG_RQ_ALLOC_TIME 27	/* record rq->alloc_time_ns */
 #define QUEUE_FLAG_HCTX_ACTIVE	28	/* at least one blk-mq hctx is active */
 #define QUEUE_FLAG_NOWAIT       29	/* device supports NOWAIT */
+#define QUEUE_FLAG_LBSZ_CHANGED	30	/* logical block size changed */
 
 #define QUEUE_FLAG_MQ_DEFAULT	((1 << QUEUE_FLAG_IO_STAT) |		\
 				 (1 << QUEUE_FLAG_SAME_COMP) |		\
-- 
2.17.1



From minwoo.im.dev at gmail.com  Tue Jan  5 07:43:03 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Tue, 5 Jan 2021 21:43:03 +0900
Subject: [PATCH 1/1] nvme: remove the unused status argument from
 nvme_trace_bio_complete
In-Reply-To: <20210105103402.3121-1-mgurtovoy@nvidia.com>
References: <20210105103402.3121-1-mgurtovoy@nvidia.com>
Message-ID: <20210105124303.GA13655@localhost.localdomain>

Hello,

Looks good to me.

On 21-01-05 10:34:02, Max Gurtovoy wrote:
> The only used argument in this function is the "req".
> 
> Signed-off-by: Max Gurtovoy <mgurtovoy at nvidia.com>

Reviewed-by: Minwoo Im <minwoo.im.dev at gmail.com>

Thanks,


From selvajove at gmail.com  Tue Jan  5 09:22:48 2021
From: selvajove at gmail.com (Selva Jove)
Date: Tue, 5 Jan 2021 19:52:48 +0530
Subject: [dm-devel] [RFC PATCH v4 2/3] block: add simple copy support
In-Reply-To: <20210104190254.GB6919@magnolia>
References: <20210104104159.74236-1-selvakuma.s1@samsung.com>
 <CGME20210104104249epcas5p458d1b5c39b5acfad4e7786eca5dd5c49@epcas5p4.samsung.com>
 <20210104104159.74236-3-selvakuma.s1@samsung.com>
 <BL0PR04MB651402CFA75F72826AC8EE1CE7D20@BL0PR04MB6514.namprd04.prod.outlook.com>
 <20210104190254.GB6919@magnolia>
Message-ID: <CAHqX9vYCRpX9FSCEaf2+xbYkB-zm7wRTmUka9zGs4D1T6nZb_A@mail.gmail.com>

Hi Darrick,


On Tue, Jan 5, 2021 at 12:33 AM Darrick J. Wong <darrick.wong at oracle.com> wrote:
>
> SelvaKumar S: This didn't show up on dm-devel, sorry for the OT reply...
>
> On Mon, Jan 04, 2021 at 12:47:11PM +0000, Damien Le Moal wrote:
> > On 2021/01/04 19:48, SelvaKumar S wrote:
> > > Add new BLKCOPY ioctl that offloads copying of one or more sources
> > > ranges to a destination in the device. Accepts copy_ranges that contains
> > > destination, no of sources and pointer to the array of source
> > > ranges. Each range_entry contains start and length of source
> > > ranges (in bytes).
> > >
> > > Introduce REQ_OP_COPY, a no-merge copy offload operation. Create
> > > bio with control information as payload and submit to the device.
> > > REQ_OP_COPY(19) is a write op and takes zone_write_lock when submitted
> > > to zoned device.
> > >
> > > If the device doesn't support copy or copy offload is disabled, then
> > > copy is emulated by allocating memory of total copy size. The source
> > > ranges are read into memory by chaining bio for each source ranges and
> > > submitting them async and the last bio waits for completion. After data
> > > is read, it is written to the destination.
> > >
> > > bio_map_kern() is used to allocate bio and add pages of copy buffer to
> > > bio. As bio->bi_private and bio->bi_end_io is needed for chaining the
> > > bio and over written, invalidate_kernel_vmap_range() for read is called
> > > in the caller.
> > >
> > > Introduce queue limits for simple copy and other helper functions.
> > > Add device limits as sysfs entries.
> > >     - copy_offload
> > >     - max_copy_sectors
> > >     - max_copy_ranges_sectors
> > >     - max_copy_nr_ranges
> > >
> > > copy_offload(= 0) is disabled by default.
> > > max_copy_sectors = 0 indicates the device doesn't support native copy.
> > >
> > > Native copy offload is not supported for stacked devices and is done via
> > > copy emulation.
> > >
> > > Signed-off-by: SelvaKumar S <selvakuma.s1 at samsung.com>
> > > Signed-off-by: Kanchan Joshi <joshi.k at samsung.com>
> > > Signed-off-by: Nitesh Shetty <nj.shetty at samsung.com>
> > > Signed-off-by: Javier Gonz?lez <javier.gonz at samsung.com>
> > > ---
> > >  block/blk-core.c          |  94 ++++++++++++++--
> > >  block/blk-lib.c           | 223 ++++++++++++++++++++++++++++++++++++++
> > >  block/blk-merge.c         |   2 +
> > >  block/blk-settings.c      |  10 ++
> > >  block/blk-sysfs.c         |  50 +++++++++
> > >  block/blk-zoned.c         |   1 +
> > >  block/bounce.c            |   1 +
> > >  block/ioctl.c             |  43 ++++++++
> > >  include/linux/bio.h       |   1 +
> > >  include/linux/blk_types.h |  15 +++
> > >  include/linux/blkdev.h    |  13 +++
> > >  include/uapi/linux/fs.h   |  13 +++
>
> This series should also be cc'd to linux-api since you're adding a new
> userspace api.
>

Sure. Will cc linux-api

>
> Alternately, save yourself the trouble of passing userspace API review
> by hooking this up to the existing copy_file_range call in the vfs.  /me
> hopes you sent blktests to check the operation of this thing, since none
> of the original patches made it to this list.
>

As the initial version had only source bdev, copy_file_rage call was not
viable. With this version, we have two bdev for source and destination.
I'll relook at that. Sure. Will add a new blktests for simple copy.

>
> If you really /do/ need a new kernel call for this, then please send in
> a manpage documenting the fields of struct range_entry and copy_range,
> and how users are supposed to use this.
>

Sure. Will send a manpage documentation once the plumbing is concrete.

> <now jumping to the ioctl definition because Damien already reviewed the
> plumbing...>
>
> > > diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
> > > index f44eb0a04afd..5cadb176317a 100644
> > > --- a/include/uapi/linux/fs.h
> > > +++ b/include/uapi/linux/fs.h
> > > @@ -64,6 +64,18 @@ struct fstrim_range {
> > >     __u64 minlen;
> > >  };
> > >
> > > +struct range_entry {
> > > +   __u64 src;
>
> Is this an offset?  Or the fd of an open bdev?

This is the source offset.

>
> > > +   __u64 len;
> > > +};
> > > +
> > > +struct copy_range {
> > > +   __u64 dest;
> > > +   __u64 nr_range;
> > > +   __u64 range_list;
>
> Hm, I think this is a pointer?  Why not just put the range_entry array
> at the end of struct copy_range?
>

As the size of the range_entry array can change dynamically depending on
nr_range, it was difficult to do copy_from_user() on copy_range structure in the
ioctl. So I decided to keep that as a pointer to range_entry array
instead of keeping
array at the end.

> > > +   __u64 rsvd;
>
> Also needs a flags argument so we don't have to add BLKCOPY2 in like 3
> months.
>

'rsvd' field is kept to support future copies. Will rename it.

> --D
>
> > > +};
> > > +
> > >  /* extent-same (dedupe) ioctls; these MUST match the btrfs ioctl definitions */
> > >  #define FILE_DEDUPE_RANGE_SAME             0
> > >  #define FILE_DEDUPE_RANGE_DIFFERS  1
> > > @@ -184,6 +196,7 @@ struct fsxattr {
> > >  #define BLKSECDISCARD _IO(0x12,125)
> > >  #define BLKROTATIONAL _IO(0x12,126)
> > >  #define BLKZEROOUT _IO(0x12,127)
> > > +#define BLKCOPY _IOWR(0x12, 128, struct copy_range)
> > >  /*
> > >   * A jump here: 130-131 are reserved for zoned block devices
> > >   * (see uapi/linux/blkzoned.h)
> > >
> >
> >
> > --
> > Damien Le Moal
> > Western Digital Research
> >
> >
> >
> > --
> > dm-devel mailing list
> > dm-devel at redhat.com
> > https://www.redhat.com/mailman/listinfo/dm-devel
> >

Thanks,
Selva


From hch at lst.de  Tue Jan  5 10:02:14 2021
From: hch at lst.de (Christoph Hellwig)
Date: Tue, 5 Jan 2021 16:02:14 +0100
Subject: [PATCH V4 1/1] block: reject I/O for same fd if block size changed
In-Reply-To: <20210105122717.2568-2-minwoo.im.dev@gmail.com>
References: <20210105122717.2568-1-minwoo.im.dev@gmail.com>
 <20210105122717.2568-2-minwoo.im.dev@gmail.com>
Message-ID: <20210105150214.GA16251@lst.de>

Looks good to me, thanks a lot!

Reviewed-by: Christoph Hellwig <hch at lst.de>


From minwoo.im.dev at gmail.com  Tue Jan  5 14:11:54 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Wed, 6 Jan 2021 04:11:54 +0900
Subject: [PATCH 2/6] nvme-core: introduce complete failed request
In-Reply-To: <20210105071936.25097-3-lengchao@huawei.com>
References: <20210105071936.25097-1-lengchao@huawei.com>
 <20210105071936.25097-3-lengchao@huawei.com>
Message-ID: <20210105191154.GA4426@localhost.localdomain>

Hello,

On 21-01-05 15:19:32, Chao Leng wrote:
> When a request is queued failed, if the fail status is not
> BLK_STS_RESOURCE, BLK_STS_DEV_RESOURCE, BLK_STS_ZONE_RESOURCE,
> the request is need to complete with nvme_complete_rq in queue_rq.
> So introduce nvme_try_complete_failed_req.
> The request is needed to complete with NVME_SC_HOST_PATH_ERROR in
> nvmf_fail_nonready_command and queue_rq.
> So introduce nvme_complete_failed_req.
> For details, see the subsequent patches.
> 
> Signed-off-by: Chao Leng <lengchao at huawei.com>
> ---
>  drivers/nvme/host/nvme.h | 18 ++++++++++++++++++
>  1 file changed, 18 insertions(+)
> 
> diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
> index bfcedfa4b057..1a0bddb9158f 100644
> --- a/drivers/nvme/host/nvme.h
> +++ b/drivers/nvme/host/nvme.h
> @@ -649,6 +649,24 @@ void nvme_put_ns_from_disk(struct nvme_ns_head *head, int idx);
>  extern const struct attribute_group *nvme_ns_id_attr_groups[];
>  extern const struct block_device_operations nvme_ns_head_ops;
>  
> +static inline void nvme_complete_failed_req(struct request *req)
> +{
> +	nvme_req(req)->status = NVME_SC_HOST_PATH_ERROR;
> +	blk_mq_set_request_complete(req);
> +	nvme_complete_rq(req);
> +}
> +
> +static inline blk_status_t nvme_try_complete_failed_req(struct request *req,
> +							blk_status_t ret)
> +{
> +	if (ret == BLK_STS_RESOURCE || ret == BLK_STS_DEV_RESOURCE ||
> +	    ret == BLK_STS_ZONE_RESOURCE)
> +		return ret;

If it has nothing to do with various conditions, can we have this if
to switch just like the other function in the same file does:

	switch (ret) {
	case BLK_STS_RESOURCE:
	case BLK_STS_DEV_RESOURCE:
	case BLK_STS_ZONE_RESOURCE:
		return ret;
	default:
		nvme_complete_failed_req(req);
		return BLK_STS_OK;
	}

> +
> +	nvme_complete_failed_req(req);
> +	return BLK_STS_OK;
> +}
> +

Can we have these two functions along side with nvme_try_complete_req()
by moving declaration of nvme_coplete_rq() a little bit up ?

>  #ifdef CONFIG_NVME_MULTIPATH
>  static inline bool nvme_ctrl_use_ana(struct nvme_ctrl *ctrl)
>  {
> -- 
> 2.16.4
> 

Thanks,


From minwoo.im.dev at gmail.com  Tue Jan  5 14:16:38 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Wed, 6 Jan 2021 04:16:38 +0900
Subject: [PATCH 1/6] blk-mq: introduce blk_mq_set_request_complete
In-Reply-To: <20210105071936.25097-2-lengchao@huawei.com>
References: <20210105071936.25097-1-lengchao@huawei.com>
 <20210105071936.25097-2-lengchao@huawei.com>
Message-ID: <20210105191638.GB4426@localhost.localdomain>

Hello,

On 21-01-05 15:19:31, Chao Leng wrote:
> In some scenarios, nvme need setting the state of request to
> MQ_RQ_COMPLETE. So add an inline function blk_mq_set_request_complete.
> For details, see the subsequent patches.
> 
> Signed-off-by: Chao Leng <lengchao at huawei.com>
> ---
>  include/linux/blk-mq.h | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h
> index e7482e6ad3ec..cee72d31054d 100644
> --- a/include/linux/blk-mq.h
> +++ b/include/linux/blk-mq.h
> @@ -493,6 +493,11 @@ static inline int blk_mq_request_completed(struct request *rq)
>  	return blk_mq_rq_state(rq) == MQ_RQ_COMPLETE;
>  }
>  
> +static inline void blk_mq_set_request_complete(struct request *rq)
> +{
> +	WRITE_ONCE(rq->state, MQ_RQ_COMPLETE);
> +}
> +

Maybe we can have this newly added helper with updating caller
in blk_mq_complete_request_remote() also ?

Thanks,


From minwoo.im.dev at gmail.com  Tue Jan  5 14:31:57 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Wed, 6 Jan 2021 04:31:57 +0900
Subject: [PATCH] nvme: trace: parse format nvm command in detail
In-Reply-To: <20210104155343.GA26034@michal-desk>
References: <20210104155343.GA26034@michal-desk>
Message-ID: <20210105193157.GC4426@localhost.localdomain>

Hello,

On 21-01-04 16:53:43, Michal Krakowiak wrote:
> FTrace does not parse NVMe commands consistently. There are commands
> that are being parsed in detail and commands for which the trace log
> contains only raw bytes of command dwords. Add detailed parsing of
> format nvm admin command to make the trace log more consistent and
> human-readable.
> 
> Signed-off-by: Michal Krakowiak <michal.krakowiak at intel.com>
> Acked-by: Dan Williams <dan.j.williams at intel.com>

Looks good to me unless driver decides to go to raw trace with
user-space application like blkparse according to Keith's opinion.

Actually Format command has several meaningful fields related
to LBA format and protection information slo so that I would be happy
for format command to be parsed for now.

Reviewed-by: Minwoo Im <minwoo.im.dev at gmail.com>

Thanks,

> ---
>  drivers/nvme/host/trace.c | 19 +++++++++++++++++++
>  1 file changed, 19 insertions(+)
> 
> diff --git a/drivers/nvme/host/trace.c b/drivers/nvme/host/trace.c
> index 5c3cb6928f3c..e0400de713b5 100644
> --- a/drivers/nvme/host/trace.c
> +++ b/drivers/nvme/host/trace.c
> @@ -102,6 +102,23 @@ static const char *nvme_trace_get_lba_status(struct trace_seq *p,
>  	return ret;
>  }
> 
> +static const char *nvme_trace_admin_format_nvm(struct trace_seq *p, u8 *cdw10)
> +{
> +	const char *ret = trace_seq_buffer_ptr(p);
> +	u8 lbaf = cdw10[0] & 0xF;
> +	u8 mset = (cdw10[0] >> 4) & 0x1;
> +	u8 pi = (cdw10[0] >> 5) & 0x7;
> +	u8 pil = cdw10[1] & 0x1;
> +	u8 ses = (cdw10[1] >> 1) & 0x7;
> +
> +	trace_seq_printf(p, "lbaf=%u, mset=%u, pi=%u, pil=%u, ses=%u",
> +			lbaf, mset, pi, pil, ses);
> +
> +	trace_seq_putc(p, 0);
> +
> +	return ret;
> +}
> +
>  static const char *nvme_trace_read_write(struct trace_seq *p, u8 *cdw10)
>  {
>  	const char *ret = trace_seq_buffer_ptr(p);
> @@ -159,6 +176,8 @@ const char *nvme_trace_parse_admin_cmd(struct trace_seq *p,
>  		return nvme_trace_admin_get_features(p, cdw10);
>  	case nvme_admin_get_lba_status:
>  		return nvme_trace_get_lba_status(p, cdw10);
> +	case nvme_admin_format_nvm:
> +		return nvme_trace_admin_format_nvm(p, cdw10);
>  	default:
>  		return nvme_trace_common(p, cdw10);
>  	}
> --
> 2.20.1
> 
> 
> _______________________________________________
> Linux-nvme mailing list
> Linux-nvme at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-nvme


From sagi at grimberg.me  Tue Jan  5 14:45:21 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Tue, 5 Jan 2021 11:45:21 -0800
Subject: kernel panic in nvmet_tcp when receiving malformed admin command
In-Reply-To: <DS7PR19MB4439372515F931BA5A1578ABEED30@DS7PR19MB4439.namprd19.prod.outlook.com>
References: <BL0PR1901MB2067C827A2D826C0FBFE985591320@BL0PR1901MB2067.namprd19.prod.outlook.com>
 <cee26269-c9c3-7ce7-8486-4ed16a632e44@grimberg.me>
 <BL0PR1901MB20671CF789D8C246AF911B4D91330@BL0PR1901MB2067.namprd19.prod.outlook.com>
 <DS7PR19MB4439372515F931BA5A1578ABEED30@DS7PR19MB4439.namprd19.prod.outlook.com>
Message-ID: <dec5fc1d-62d6-1c1e-e2f8-4aa5aeb084af@grimberg.me>


> Hi Sagi, is the patch addressing the below issue is already out there?

No, thanks for reminding me, I'll have a look into this.


From klayph at gmail.com  Tue Jan  5 17:49:37 2021
From: klayph at gmail.com (klayph at gmail.com)
Date: Tue,  5 Jan 2021 14:49:37 -0800
Subject: [PATCH 0/2] nvme: Support for fused NVME_IOCTL_SUBMIT_IO
Message-ID: <20210105224939.1336-1-clay.mayers@kioxia.com>

From: Clay Mayers <clay.mayers at kioxia.com>

Enables fused compare/write to be issued from user mode.

The first patch allows a pair of pass through requests
to be linked and submitted as a fused pair to the nvme
device queue.  The second patch exposes it through an
nvme ioctl so a cmp/write can be issued from user mode.

There was a question regarding Linux support for this
functionality in nvme-cli.  With these patches, that
would be possible.

https://github.com/linux-nvme/nvme-cli/issues/318

Clay Mayers (2):
  nvme: support fused nvme requests
  nvme: support fused NVME_IOCTL_SUBMIT_IO

 drivers/nvme/host/core.c | 261 ++++++++++++++++++++++++++++++---------
 drivers/nvme/host/nvme.h |   2 +
 drivers/nvme/host/pci.c  |  32 ++++-
 3 files changed, 234 insertions(+), 61 deletions(-)

-- 
2.27.0



From klayph at gmail.com  Tue Jan  5 17:49:38 2021
From: klayph at gmail.com (klayph at gmail.com)
Date: Tue,  5 Jan 2021 14:49:38 -0800
Subject: [PATCH 1/2] nvme: support fused nvme requests
In-Reply-To: <20210105224939.1336-1-clay.mayers@kioxia.com>
References: <20210105224939.1336-1-clay.mayers@kioxia.com>
Message-ID: <20210105224939.1336-2-clay.mayers@kioxia.com>

From: Clay Mayers <mayerc at kioxia.com>

Adds support for fused nvme commands to be tunneled through a blk_mq
queue and submitted atomically to an nvme device queue.

If the nvme cmnd has the first fused flag set, nvme_request.nrq2 points
to the nvme_request for the second fused command. Instead of submitting
the first request, its cmnd is saved in the second command's
nvme_request to be submitted as a pair once the second request is
processed by nvme_queue_rq().

Signed-off-by: Clay Mayers <clay.mayers at kioxia.com>
---
 drivers/nvme/host/core.c |  1 +
 drivers/nvme/host/nvme.h |  2 ++
 drivers/nvme/host/pci.c  | 32 +++++++++++++++++++++++++++++++-
 3 files changed, 34 insertions(+), 1 deletion(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 9a270e49df17..a498cf6a9eaf 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -514,6 +514,7 @@ static inline void nvme_clear_nvme_request(struct request *req)
 	if (!(req->rq_flags & RQF_DONTPREP)) {
 		nvme_req(req)->retries = 0;
 		nvme_req(req)->flags = 0;
+		nvme_req(req)->nrq2 = NULL;
 		req->rq_flags |= RQF_DONTPREP;
 	}
 }
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 567f7ad18a91..187dde1f11fe 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -157,6 +157,8 @@ struct nvme_request {
 	u8			flags;
 	u16			status;
 	struct nvme_ctrl	*ctrl;
+	struct nvme_request	*nrq2;	/* Points to second fused request */
+	struct nvme_command	cmnd;	/* Saved fused first cmnd */
 };
 
 /*
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 3be352403839..c24729e100bc 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -491,6 +491,30 @@ static inline void nvme_write_sq_db(struct nvme_queue *nvmeq, bool write_sq)
 	nvmeq->last_sq_tail = nvmeq->sq_tail;
 }
 
+/**
+ * nvme_submit_cmd2() - Copy fused commands into a queue and ring the doorbell
+ * @nvmeq: The queue to use
+ * @cmd: The first command to send
+ * @cmd2: the second command to send
+ * @write_sq: whether to write to the SQ doorbell
+ */
+static void nvme_submit_cmd2(struct nvme_queue *nvmeq, struct nvme_command *cmd,
+			     struct nvme_command *cmd2, bool write_sq)
+{
+	spin_lock(&nvmeq->sq_lock);
+	memcpy(nvmeq->sq_cmds + (nvmeq->sq_tail << nvmeq->sqes),
+		cmd, sizeof(*cmd));
+	if (++nvmeq->sq_tail == nvmeq->q_depth)
+		nvmeq->sq_tail = 0;
+	memcpy(nvmeq->sq_cmds + (nvmeq->sq_tail << nvmeq->sqes),
+		cmd2, sizeof(*cmd2));
+	if (++nvmeq->sq_tail == nvmeq->q_depth)
+		nvmeq->sq_tail = 0;
+	nvme_write_sq_db(nvmeq, write_sq);
+	spin_unlock(&nvmeq->sq_lock);
+}
+
+
 /**
  * nvme_submit_cmd() - Copy a command into a queue and ring the doorbell
  * @nvmeq: The queue to use
@@ -918,7 +942,13 @@ static blk_status_t nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
 	}
 
 	blk_mq_start_request(req);
-	nvme_submit_cmd(nvmeq, &cmnd, bd->last);
+
+	if (cmnd.common.flags & NVME_CMD_FUSE_FIRST)
+		memcpy(&nvme_req(req)->nrq2->cmnd, &cmnd, sizeof(cmnd));
+	else if (cmnd.common.flags & NVME_CMD_FUSE_SECOND)
+		nvme_submit_cmd2(nvmeq, &nvme_req(req)->cmnd, &cmnd, bd->last);
+	else
+		nvme_submit_cmd(nvmeq, &cmnd, bd->last);
 	return BLK_STS_OK;
 out_unmap_data:
 	nvme_unmap_data(dev, req);
-- 
2.27.0



From klayph at gmail.com  Tue Jan  5 17:49:39 2021
From: klayph at gmail.com (klayph at gmail.com)
Date: Tue,  5 Jan 2021 14:49:39 -0800
Subject: [PATCH 2/2] nvme: support fused NVME_IOCTL_SUBMIT_IO
In-Reply-To: <20210105224939.1336-1-clay.mayers@kioxia.com>
References: <20210105224939.1336-1-clay.mayers@kioxia.com>
Message-ID: <20210105224939.1336-3-clay.mayers@kioxia.com>

From: Clay Mayers <mayerc at kioxia.com>

Extends the functionality of the NVME_IOCTL_SUBMIT_IO ioctl to support
a pair of fused nvme_user_io requests.

When submitting a fused pair, an array of two nvme_user_io structs are
supplied when invoking NVME_IOCTL_SUBMIT_IO ioctl.  Rather than
introduce a new ioctl code, the presence of a fused pair is indicated
by the nvme_user_io.flags having the value of NVME_CMD_FUSED_FIRST.
This then indicates a second nvme_user_io struct follows the first with
an nvme_user_io.flags set to NVME_CMD_FUSED_SECOND.

A fused pair may fail to submit with -EWOULDBLOCK.  This indicates the
device queue selected for the first command didn't have a tag available
when the request for the second command was created.

Signed-off-by: Clay Mayers <clay.mayers at kioxia.com>
---
 drivers/nvme/host/core.c | 260 ++++++++++++++++++++++++++++++---------
 1 file changed, 200 insertions(+), 60 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index a498cf6a9eaf..ce5d2a9a08a8 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -1468,16 +1468,40 @@ static void __user *nvme_to_user_ptr(uintptr_t ptrval)
 	return (void __user *)ptrval;
 }
 
-static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
+struct nvme_user_io_req {
+	struct nvme_command cmd;
+	struct request *rq;
+	struct bio *bio;	/* bio in rq at the time of allocation */
+	void *meta;
+	void __user *udata;
+	void __user *umeta;
+	unsigned int len;
+	unsigned int mlen;
+	u32 mseed;
+};
+
+static void nvme_free_io(struct nvme_user_io_req *nrq)
+{
+	if (!nrq)
+		return;
+	kfree(nrq->meta);
+	if (nrq->bio)
+		blk_rq_unmap_user(nrq->bio);
+	if (nrq->rq)
+		blk_mq_free_request(nrq->rq);
+	nrq->meta = NULL;
+	nrq->bio = NULL;
+	nrq->rq = NULL;
+}
+
+static int nvme_prep_io(struct nvme_ns *ns, struct nvme_user_io_req *nrq,
+			struct nvme_user_io __user *uio, int size)
 {
 	struct nvme_user_io io;
-	struct nvme_command c;
-	unsigned length, meta_len;
-	void __user *metadata;
 
-	if (copy_from_user(&io, uio, sizeof(io)))
+	if (unlikely(copy_from_user(&io, uio, size)))
 		return -EFAULT;
-	if (io.flags)
+	if (unlikely(io.flags & ~(NVME_CMD_FUSE_FIRST|NVME_CMD_FUSE_SECOND)))
 		return -EINVAL;
 
 	switch (io.opcode) {
@@ -1489,33 +1513,160 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
 		return -EINVAL;
 	}
 
-	length = (io.nblocks + 1) << ns->lba_shift;
-	meta_len = (io.nblocks + 1) * ns->ms;
-	metadata = nvme_to_user_ptr(io.metadata);
+	nrq->udata = nvme_to_user_ptr(io.addr);
+	nrq->len = (io.nblocks + 1) << ns->lba_shift;
+	nrq->umeta = nvme_to_user_ptr(io.metadata);
+	nrq->mlen = (io.nblocks + 1) * ns->ms;
+	nrq->mseed = lower_32_bits(io.slba);
+	nrq->bio = nrq->meta = NULL;
 
 	if (ns->features & NVME_NS_EXT_LBAS) {
-		length += meta_len;
-		meta_len = 0;
-	} else if (meta_len) {
+		nrq->len += nrq->mlen;
+		nrq->mlen = 0;
+	} else if (nrq->mlen) {
 		if ((io.metadata & 3) || !io.metadata)
 			return -EINVAL;
 	}
 
-	memset(&c, 0, sizeof(c));
-	c.rw.opcode = io.opcode;
-	c.rw.flags = io.flags;
-	c.rw.nsid = cpu_to_le32(ns->head->ns_id);
-	c.rw.slba = cpu_to_le64(io.slba);
-	c.rw.length = cpu_to_le16(io.nblocks);
-	c.rw.control = cpu_to_le16(io.control);
-	c.rw.dsmgmt = cpu_to_le32(io.dsmgmt);
-	c.rw.reftag = cpu_to_le32(io.reftag);
-	c.rw.apptag = cpu_to_le16(io.apptag);
-	c.rw.appmask = cpu_to_le16(io.appmask);
-
-	return nvme_submit_user_cmd(ns->queue, &c,
-			nvme_to_user_ptr(io.addr), length,
-			metadata, meta_len, lower_32_bits(io.slba), NULL, 0);
+	memset(&nrq->cmd, 0, sizeof(nrq->cmd));
+	nrq->cmd.rw.opcode = io.opcode;
+	nrq->cmd.rw.flags = io.flags;
+	nrq->cmd.rw.nsid = cpu_to_le32(ns->head->ns_id);
+	nrq->cmd.rw.slba = cpu_to_le64(io.slba);
+	nrq->cmd.rw.length = cpu_to_le16(io.nblocks);
+	nrq->cmd.rw.control = cpu_to_le16(io.control);
+	nrq->cmd.rw.dsmgmt = cpu_to_le32(io.dsmgmt);
+	nrq->cmd.rw.reftag = cpu_to_le32(io.reftag);
+	nrq->cmd.rw.apptag = cpu_to_le16(io.apptag);
+	nrq->cmd.rw.appmask = cpu_to_le16(io.appmask);
+
+	return 0;
+}
+
+static struct request *nvme_mk_req_io(struct nvme_ns *ns,
+				      struct nvme_user_io_req *nrq,
+				      blk_mq_req_flags_t flags, int qid,
+				      int timeout)
+{
+	bool write = nvme_is_write(&nrq->cmd);
+	struct request_queue *q = ns->queue;
+	struct gendisk *disk = ns->disk;
+	struct request *rq;
+	struct bio *bio = NULL;
+	void *meta = NULL;
+	int ret;
+
+	rq = nvme_alloc_request(q, &nrq->cmd, flags, qid);
+	if (unlikely(IS_ERR(rq)))
+		return rq;
+
+	rq->timeout = timeout ? timeout : ADMIN_TIMEOUT;
+	nvme_req(rq)->flags |= NVME_REQ_USERCMD;
+
+	if (nrq->udata && nrq->len) {
+		ret = blk_rq_map_user(q, rq, NULL, nrq->udata, nrq->len,
+				GFP_KERNEL);
+		if (ret)
+			goto out;
+		bio = rq->bio;
+		bio->bi_disk = disk;
+		if (disk && nrq->umeta && nrq->mlen) {
+			meta = nvme_add_user_metadata(bio, nrq->umeta, nrq->mlen,
+					nrq->mseed, write);
+			if (IS_ERR(meta)) {
+				ret = PTR_ERR(meta);
+				goto out_unmap;
+			}
+			nrq->meta = meta;
+		}
+	}
+	nrq->bio = bio;
+	return rq;
+out_unmap:
+	if (bio)
+		blk_rq_unmap_user(bio);
+ out:
+	blk_mq_free_request(rq);
+	return ERR_PTR(ret);
+}
+
+static int nvme_unprep_io(struct nvme_user_io_req *nrq,
+			  u64 *result)
+{
+	struct request *rq = nrq->rq;
+	int write = nvme_is_write(&nrq->cmd);
+	int ret;
+
+	if (unlikely(nvme_req(rq)->flags & NVME_REQ_CANCELLED))
+		ret = -EINTR;
+	else
+		ret = nvme_req(rq)->status;
+	if (result)
+		*result = le64_to_cpu(nvme_req(rq)->result.u64);
+	if (nrq->meta && !ret && !write) {
+		if (copy_to_user(nrq->umeta, nrq->meta, nrq->mlen))
+			ret = -EFAULT;
+	}
+	nvme_free_io(nrq);
+	return ret;
+}
+
+/* support both NVME_IOCTL_SUBMIT_IO and NVME_IOCTL_SUBMIT_IO32 */
+static int nvme_submit_io(struct nvme_ns *ns, void __user *uio,
+			  int size)
+{
+	struct nvme_user_io_req nrq, nrq2;
+	struct request *rq, *rq2;
+	int ret, fused;
+
+	ret = nvme_prep_io(ns, &nrq, uio, size);
+	if (unlikely(ret))
+		return ret;
+	fused = (nrq.cmd.common.flags == NVME_CMD_FUSE_FIRST);
+	if (fused) {
+		ret = nvme_prep_io(ns, &nrq2, uio+size, size);
+		if (unlikely(ret))
+			return ret;
+		if (unlikely(nrq2.cmd.common.flags != NVME_CMD_FUSE_SECOND))
+			return -EINVAL;
+	} else if (unlikely(nrq.cmd.common.flags)) {
+		return -EINVAL;
+	}
+	rq = nvme_mk_req_io(ns, &nrq, 0, NVME_QID_ANY, 0);
+	if (unlikely(IS_ERR(rq)))
+		return PTR_ERR(rq);
+	nrq.rq = rq;
+	if (fused) {
+		DECLARE_COMPLETION_ONSTACK(wait);
+
+		rq2 = nvme_mk_req_io(ns, &nrq2, BLK_MQ_REQ_NOWAIT,
+				     nvme_req_qid(rq), 0);
+		if (unlikely(IS_ERR(rq2))) {
+			nvme_free_io(&nrq);
+			return PTR_ERR(rq2);
+		}
+		nvme_req(rq)->nrq2 = nvme_req(rq2);
+		nrq2.rq = rq2;
+
+		rq->cmd_flags |= REQ_NOMERGE;
+		rq2->cmd_flags |= REQ_NOMERGE;
+		rq->end_io_data = &wait;
+		blk_execute_rq_nowait(rq->q, ns->disk, rq, false, nvme_end_sync_rq);
+		nvme_execute_passthru_rq(rq2);
+
+		/*
+		 * both will be complete at this point, but nvme spec doesn't
+		 * specify cqe ordering for fused operations so wait for the
+		 * first to complete as well
+		 */
+		wait_for_completion_io(&wait);
+		nvme_unprep_io(&nrq, NULL);
+		ret = nvme_unprep_io(&nrq2, NULL);
+	} else {
+		nvme_execute_passthru_rq(rq);
+		ret = nvme_unprep_io(&nrq, NULL);
+	}
+	return ret;
 }
 
 static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
@@ -1672,6 +1823,23 @@ static int nvme_handle_ctrl_ioctl(struct nvme_ns *ns, unsigned int cmd,
 	return ret;
 }
 
+struct nvme_user_io32 {
+	__u8	opcode;
+	__u8	flags;
+	__u16	control;
+	__u16	nblocks;
+	__u16	rsvd;
+	__u64	metadata;
+	__u64	addr;
+	__u64	slba;
+	__u32	dsmgmt;
+	__u32	reftag;
+	__u16	apptag;
+	__u16	appmask;
+} __attribute__((__packed__));
+
+#define NVME_IOCTL_SUBMIT_IO32	_IOW('N', 0x42, struct nvme_user_io32)
+
 static int nvme_ioctl(struct block_device *bdev, fmode_t mode,
 		unsigned int cmd, unsigned long arg)
 {
@@ -1700,8 +1868,10 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode,
 	case NVME_IOCTL_IO_CMD:
 		ret = nvme_user_cmd(ns->ctrl, ns, argp);
 		break;
+	case NVME_IOCTL_SUBMIT_IO32:
+		fallthrough;	/* structures are identical except size */
 	case NVME_IOCTL_SUBMIT_IO:
-		ret = nvme_submit_io(ns, argp);
+		ret = nvme_submit_io(ns, argp, _IOC_SIZE(cmd));
 		break;
 	case NVME_IOCTL_IO64_CMD:
 		ret = nvme_user_cmd64(ns->ctrl, ns, argp);
@@ -1717,41 +1887,11 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode,
 	return ret;
 }
 
-#ifdef CONFIG_COMPAT
-struct nvme_user_io32 {
-	__u8	opcode;
-	__u8	flags;
-	__u16	control;
-	__u16	nblocks;
-	__u16	rsvd;
-	__u64	metadata;
-	__u64	addr;
-	__u64	slba;
-	__u32	dsmgmt;
-	__u32	reftag;
-	__u16	apptag;
-	__u16	appmask;
-} __attribute__((__packed__));
-
-#define NVME_IOCTL_SUBMIT_IO32	_IOW('N', 0x42, struct nvme_user_io32)
 
+#ifdef CONFIG_COMPAT
 static int nvme_compat_ioctl(struct block_device *bdev, fmode_t mode,
 		unsigned int cmd, unsigned long arg)
 {
-	/*
-	 * Corresponds to the difference of NVME_IOCTL_SUBMIT_IO
-	 * between 32 bit programs and 64 bit kernel.
-	 * The cause is that the results of sizeof(struct nvme_user_io),
-	 * which is used to define NVME_IOCTL_SUBMIT_IO,
-	 * are not same between 32 bit compiler and 64 bit compiler.
-	 * NVME_IOCTL_SUBMIT_IO32 is for 64 bit kernel handling
-	 * NVME_IOCTL_SUBMIT_IO issued from 32 bit programs.
-	 * Other IOCTL numbers are same between 32 bit and 64 bit.
-	 * So there is nothing to do regarding to other IOCTL numbers.
-	 */
-	if (cmd == NVME_IOCTL_SUBMIT_IO32)
-		return nvme_ioctl(bdev, mode, NVME_IOCTL_SUBMIT_IO, arg);
-
 	return nvme_ioctl(bdev, mode, cmd, arg);
 }
 #else
@@ -3118,7 +3258,7 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
 	ret = nvme_configure_apst(ctrl);
 	if (ret < 0)
 		return ret;
-	
+
 	ret = nvme_configure_timestamp(ctrl);
 	if (ret < 0)
 		return ret;
-- 
2.27.0



From james.smart at broadcom.com  Tue Jan  5 18:04:43 2021
From: james.smart at broadcom.com (James Smart)
Date: Tue, 5 Jan 2021 15:04:43 -0800
Subject: [PATCH 0/2] nvme: Support for fused NVME_IOCTL_SUBMIT_IO
In-Reply-To: <20210105224939.1336-1-clay.mayers@kioxia.com>
References: <20210105224939.1336-1-clay.mayers@kioxia.com>
Message-ID: <7104fe82-7b05-b747-5529-edab6ada2082@broadcom.com>


On 1/5/2021 2:49 PM, klayph at gmail.com wrote:
> From: Clay Mayers <clay.mayers at kioxia.com>
>
> Enables fused compare/write to be issued from user mode.
>
> The first patch allows a pair of pass through requests
> to be linked and submitted as a fused pair to the nvme
> device queue.  The second patch exposes it through an
> nvme ioctl so a cmp/write can be issued from user mode.
>
> There was a question regarding Linux support for this
> functionality in nvme-cli.  With these patches, that
> would be possible.
>
> https://github.com/linux-nvme/nvme-cli/issues/318
>
> Clay Mayers (2):
>    nvme: support fused nvme requests
>    nvme: support fused NVME_IOCTL_SUBMIT_IO
>
>   drivers/nvme/host/core.c | 261 ++++++++++++++++++++++++++++++---------
>   drivers/nvme/host/nvme.h |   2 +
>   drivers/nvme/host/pci.c  |  32 ++++-
>   3 files changed, 234 insertions(+), 61 deletions(-)
>

Hmmm... I don't expect fused support to be simple. There's the whole 
notion of: submitting the two commands such that back-to-back queue_rq() 
calls are made to the transport for the same queue and the back-to-back 
calls (different request contexts) just happen to be the fused commands; 
as well as under error, if queues are frozen, then replayed, the same 
back-to-back calling sequence occurs (and I hope a freeze occuring while 
one sent another not, would recover).

And... the transports better be able to support fused commands as well.? 
nvme-fc does not as fused commands were explicitly deemed unsupported.

But - I'll look to see what you have in the patches.

-- james

-- 
This electronic communication and the information and any files transmitted 
with it, or attached to it, are confidential and are intended solely for 
the use of the individual or entity to whom it is addressed and may contain 
information that is confidential, legally privileged, protected by privacy 
laws, or otherwise restricted from disclosure to anyone else. If you are 
not the intended recipient or the person responsible for delivering the 
e-mail to the intended recipient, you are hereby notified that any use, 
copying, distributing, dissemination, forwarding, printing, or copying of 
this e-mail is strictly prohibited. If you received this e-mail in error, 
please return the e-mail to the sender, delete it from your computer, and 
destroy any printed copy of it.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 4163 bytes
Desc: S/MIME Cryptographic Signature
URL: <http://lists.infradead.org/pipermail/linux-nvme/attachments/20210105/a3e0d513/attachment.p7s>

From Damien.LeMoal at wdc.com  Tue Jan  5 18:33:57 2021
From: Damien.LeMoal at wdc.com (Damien Le Moal)
Date: Tue, 5 Jan 2021 23:33:57 +0000
Subject: [RFC PATCH v4 2/3] block: add simple copy support
References: <20210104104159.74236-1-selvakuma.s1@samsung.com>
 <CGME20210104104249epcas5p458d1b5c39b5acfad4e7786eca5dd5c49@epcas5p4.samsung.com>
 <20210104104159.74236-3-selvakuma.s1@samsung.com>
 <BL0PR04MB651402CFA75F72826AC8EE1CE7D20@BL0PR04MB6514.namprd04.prod.outlook.com>
 <CAHqX9vafJ9JwkT-oDJRfbLV0WKym-6FiTQqngcP1pk8J+zgbxQ@mail.gmail.com>
Message-ID: <BL0PR04MB6514233D8AE368455EF35AB6E7D10@BL0PR04MB6514.namprd04.prod.outlook.com>

On 2021/01/05 21:24, Selva Jove wrote:
> Thanks for the review, Damien.
> 
> On Mon, Jan 4, 2021 at 6:17 PM Damien Le Moal <Damien.LeMoal at wdc.com> wrote:
>>
>> On 2021/01/04 19:48, SelvaKumar S wrote:
>>> Add new BLKCOPY ioctl that offloads copying of one or more sources
>>> ranges to a destination in the device. Accepts copy_ranges that contains
>>> destination, no of sources and pointer to the array of source
>>> ranges. Each range_entry contains start and length of source
>>> ranges (in bytes).
>>>
>>> Introduce REQ_OP_COPY, a no-merge copy offload operation. Create
>>> bio with control information as payload and submit to the device.
>>> REQ_OP_COPY(19) is a write op and takes zone_write_lock when submitted
>>> to zoned device.
>>>
>>> If the device doesn't support copy or copy offload is disabled, then
>>> copy is emulated by allocating memory of total copy size. The source
>>> ranges are read into memory by chaining bio for each source ranges and
>>> submitting them async and the last bio waits for completion. After data
>>> is read, it is written to the destination.
>>>
>>> bio_map_kern() is used to allocate bio and add pages of copy buffer to
>>> bio. As bio->bi_private and bio->bi_end_io is needed for chaining the
>>> bio and over written, invalidate_kernel_vmap_range() for read is called
>>> in the caller.
>>>
>>> Introduce queue limits for simple copy and other helper functions.
>>> Add device limits as sysfs entries.
>>>       - copy_offload
>>>       - max_copy_sectors
>>>       - max_copy_ranges_sectors
>>>       - max_copy_nr_ranges
>>>
>>> copy_offload(= 0) is disabled by default.
>>> max_copy_sectors = 0 indicates the device doesn't support native copy.
>>>
>>> Native copy offload is not supported for stacked devices and is done via
>>> copy emulation.
>>>
>>> Signed-off-by: SelvaKumar S <selvakuma.s1 at samsung.com>
>>> Signed-off-by: Kanchan Joshi <joshi.k at samsung.com>
>>> Signed-off-by: Nitesh Shetty <nj.shetty at samsung.com>
>>> Signed-off-by: Javier Gonz?lez <javier.gonz at samsung.com>
>>> ---
>>>  block/blk-core.c          |  94 ++++++++++++++--
>>>  block/blk-lib.c           | 223 ++++++++++++++++++++++++++++++++++++++
>>>  block/blk-merge.c         |   2 +
>>>  block/blk-settings.c      |  10 ++
>>>  block/blk-sysfs.c         |  50 +++++++++
>>>  block/blk-zoned.c         |   1 +
>>>  block/bounce.c            |   1 +
>>>  block/ioctl.c             |  43 ++++++++
>>>  include/linux/bio.h       |   1 +
>>>  include/linux/blk_types.h |  15 +++
>>>  include/linux/blkdev.h    |  13 +++
>>>  include/uapi/linux/fs.h   |  13 +++
>>>  12 files changed, 458 insertions(+), 8 deletions(-)
>>>
>>> diff --git a/block/blk-core.c b/block/blk-core.c
>>> index 96e5fcd7f071..4a5cd3f53cd2 100644
>>> --- a/block/blk-core.c
>>> +++ b/block/blk-core.c
>>> @@ -719,6 +719,17 @@ static noinline int should_fail_bio(struct bio *bio)
>>>  }
>>>  ALLOW_ERROR_INJECTION(should_fail_bio, ERRNO);
>>>
>>> +static inline int bio_check_copy_eod(struct bio *bio, sector_t start,
>>> +             sector_t nr_sectors, sector_t maxsector)
>>> +{
>>> +     if (nr_sectors && maxsector &&
>>> +         (nr_sectors > maxsector || start > maxsector - nr_sectors)) {
>>> +             handle_bad_sector(bio, maxsector);
>>> +             return -EIO;
>>> +     }
>>> +     return 0;
>>> +}
>>> +
>>>  /*
>>>   * Check whether this bio extends beyond the end of the device or partition.
>>>   * This may well happen - the kernel calls bread() without checking the size of
>>> @@ -737,6 +748,65 @@ static inline int bio_check_eod(struct bio *bio, sector_t maxsector)
>>>       return 0;
>>>  }
>>>
>>> +/*
>>> + * Check for copy limits and remap source ranges if needed.
>>> + */
>>> +static int blk_check_copy(struct bio *bio)
>>> +{
>>> +     struct block_device *p = NULL;
>>> +     struct request_queue *q = bio->bi_disk->queue;
>>> +     struct blk_copy_payload *payload;
>>> +     int i, maxsector, start_sect = 0, ret = -EIO;
>>> +     unsigned short nr_range;
>>> +
>>> +     rcu_read_lock();
>>> +
>>> +     p = __disk_get_part(bio->bi_disk, bio->bi_partno);
>>> +     if (unlikely(!p))
>>> +             goto out;
>>> +     if (unlikely(should_fail_request(p, bio->bi_iter.bi_size)))
>>> +             goto out;
>>> +     if (unlikely(bio_check_ro(bio, p)))
>>> +             goto out;
>>> +
>>> +     maxsector =  bdev_nr_sectors(p);
>>> +     start_sect = p->bd_start_sect;
>>> +
>>> +     payload = bio_data(bio);
>>> +     nr_range = payload->copy_range;
>>> +
>>> +     /* cannot handle copy crossing nr_ranges limit */
>>> +     if (payload->copy_range > q->limits.max_copy_nr_ranges)
>>> +             goto out;
>>
>> If payload->copy_range indicates the number of ranges to be copied, you should
>> name it payload->copy_nr_ranges.
>>
> 
> Agreed. Will rename the entries.
> 
>>> +
>>> +     /* cannot handle copy more than copy limits */
>>
>> Why ? You could loop... Similarly to discard, zone reset etc.
>>
> 
> Sure. Will add the support for handling copy larger than device limits.
> 
>>
>>> +     if (payload->copy_size > q->limits.max_copy_sectors)
>>> +             goto out;
>>
>> Shouldn't the list of source ranges give the total size to be copied ?
>> Otherwise, if payload->copy_size is user provided, you would need to check that
>> the sum of the source ranges actually is equal to copy_size, no ? That means
>> that dropping copy_size sound like the right thing to do here.
>>
> 
> payload->copy_size is used in copy emulation to allocate the buffer.
> Let me check
> one more time if it is possible to do without this.

If this is used for the emulation only, then it should be a local variable in
the emulation helper.

[...]
>>
>>> +             if (unlikely(blk_check_copy(bio)))
>>> +                     goto end_io;
>>> +             break;
>>>       case REQ_OP_SECURE_ERASE:
>>>               if (!blk_queue_secure_erase(q))
>>>                       goto not_supported;
>>> diff --git a/block/blk-lib.c b/block/blk-lib.c
>>> index 752f9c722062..4c0f12e2ed7c 100644
>>> --- a/block/blk-lib.c
>>> +++ b/block/blk-lib.c
>>> @@ -150,6 +150,229 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
>>>  }
>>>  EXPORT_SYMBOL(blkdev_issue_discard);
>>>
>>> +int blk_copy_offload(struct block_device *bdev, struct blk_copy_payload *payload,
>>> +             sector_t dest, gfp_t gfp_mask)
>>> +{
>>> +     struct bio *bio;
>>> +     int ret, total_size;
>>> +
>>> +     bio = bio_alloc(gfp_mask, 1);
>>> +     bio->bi_iter.bi_sector = dest;
>>> +     bio->bi_opf = REQ_OP_COPY | REQ_NOMERGE;
>>> +     bio_set_dev(bio, bdev);
>>> +
>>> +     total_size = struct_size(payload, range, payload->copy_range);
>>> +     ret = bio_add_page(bio, virt_to_page(payload), total_size,
>>
>> How is payload allocated ? If it is a structure on-stack in the caller, I am not
>> sure it would be wise to do an IO using the thread stack page...
>>
>>> +                                        offset_in_page(payload));
>>> +     if (ret != total_size) {
>>> +             ret = -ENOMEM;
>>> +             bio_put(bio);
>>> +             goto err;
>>> +     }
>>> +
>>> +     ret = submit_bio_wait(bio);
>>> +err:
>>> +     bio_put(bio);
>>> +     return ret;
>>> +
>>> +}
>>> +
>>> +int blk_read_to_buf(struct block_device *bdev, struct blk_copy_payload *payload,
>>> +             gfp_t gfp_mask, void **buf_p)
>>> +{
>>> +     struct request_queue *q = bdev_get_queue(bdev);
>>> +     struct bio *bio, *parent = NULL;
>>> +     void *buf = NULL;
>>> +     bool is_vmalloc;
>>> +     int i, nr_srcs, copy_len, ret, cur_size, t_len = 0;
>>> +
>>> +     nr_srcs = payload->copy_range;
>>> +     copy_len = payload->copy_size << SECTOR_SHIFT;
>>> +
>>> +     buf = kvmalloc(copy_len, gfp_mask);
>>> +     if (!buf)
>>> +             return -ENOMEM;
>>> +     is_vmalloc = is_vmalloc_addr(buf);
>>> +
>>> +     for (i = 0; i < nr_srcs; i++) {
>>> +             cur_size = payload->range[i].len << SECTOR_SHIFT;
>>> +
>>> +             bio = bio_map_kern(q, buf + t_len, cur_size, gfp_mask);
>>> +             if (IS_ERR(bio)) {
>>> +                     ret = PTR_ERR(bio);
>>> +                     goto out;
>>> +             }
>>> +
>>> +             bio->bi_iter.bi_sector = payload->range[i].src;
>>> +             bio->bi_opf = REQ_OP_READ;
>>> +             bio_set_dev(bio, bdev);
>>> +             bio->bi_end_io = NULL;
>>> +             bio->bi_private = NULL;
>>> +
>>> +             if (parent) {
>>> +                     bio_chain(parent, bio);
>>> +                     submit_bio(parent);
>>> +             }
>>> +
>>> +             parent = bio;
>>> +             t_len += cur_size;
>>> +     }
>>> +
>>> +     ret = submit_bio_wait(bio);
>>> +     bio_put(bio);
>>> +     if (is_vmalloc)
>>> +             invalidate_kernel_vmap_range(buf, copy_len);
>>> +     if (ret)
>>> +             goto out;
>>> +
>>> +     *buf_p = buf;
>>> +     return 0;
>>> +out:
>>> +     kvfree(buf);
>>> +     return ret;
>>> +}
>>> +
>>> +int blk_write_from_buf(struct block_device *bdev, void *buf, sector_t dest,
>>> +             int copy_len, gfp_t gfp_mask)
>>> +{
>>> +     struct request_queue *q = bdev_get_queue(bdev);
>>> +     struct bio *bio;
>>> +     int ret;
>>> +
>>> +     bio = bio_map_kern(q, buf, copy_len, gfp_mask);
>>> +     if (IS_ERR(bio)) {
>>> +             ret = PTR_ERR(bio);
>>> +             goto out;
>>> +     }
>>> +     bio_set_dev(bio, bdev);
>>> +     bio->bi_opf = REQ_OP_WRITE;
>>> +     bio->bi_iter.bi_sector = dest;
>>> +
>>> +     bio->bi_end_io = NULL;
>>> +     ret = submit_bio_wait(bio);
>>> +     bio_put(bio);
>>> +out:
>>> +     return ret;
>>> +}
>>> +
>>> +int blk_prepare_payload(struct block_device *bdev, int nr_srcs, struct range_entry *rlist,
>>> +             gfp_t gfp_mask, struct blk_copy_payload **payload_p)
>>> +{
>>> +
>>> +     struct request_queue *q = bdev_get_queue(bdev);
>>> +     struct blk_copy_payload *payload;
>>> +     sector_t bs_mask;
>>> +     sector_t src_sects, len = 0, total_len = 0;
>>> +     int i, ret, total_size;
>>> +
>>> +     if (!q)
>>> +             return -ENXIO;
>>> +
>>> +     if (!nr_srcs)
>>> +             return -EINVAL;
>>> +
>>> +     if (bdev_read_only(bdev))
>>> +             return -EPERM;
>>> +
>>> +     bs_mask = (bdev_logical_block_size(bdev) >> 9) - 1;
>>> +
>>> +     total_size = struct_size(payload, range, nr_srcs);
>>> +     payload = kmalloc(total_size, gfp_mask);
>>> +     if (!payload)
>>> +             return -ENOMEM;
>>
>> OK. So this is what goes into the bio. The function blk_copy_offload() assumes
>> this is at most one page, so total_size <= PAGE_SIZE. Where is that checked ?
>>
> 
> CMIIW. As payload was allocated via kmalloc, it would be represented by a single
> contiguous segment. In case it crosses one page, rely on multi-page bio_vec to
> cover it.

That is not how I understand the code. If the allocation is more than one page,
you still need to add ALL pages to the BIO. What the multi-page bvec code will
do is to use a single bvec for all physically contiguous pages instead of adding
one bvec per page.

Thinking more about it, I think the function blk_copy_offload() could simply use
bio_map_kern() to allocate and prepare the BIO. That will avoid the need for the
add page loop.

> 
>>> +
>>> +     for (i = 0; i < nr_srcs; i++) {
>>> +             /*  copy payload provided are in bytes */
>>> +             src_sects = rlist[i].src;
>>> +             if (src_sects & bs_mask) {
>>> +                     ret =  -EINVAL;
>>> +                     goto err;
>>> +             }
>>> +             src_sects = src_sects >> SECTOR_SHIFT;
>>> +
>>> +             if (len & bs_mask) {
>>> +                     ret = -EINVAL;
>>> +                     goto err;
>>> +             }
>>> +
>>> +             len = rlist[i].len >> SECTOR_SHIFT;
>>> +
>>> +             total_len += len;
>>> +
>>> +             WARN_ON_ONCE((src_sects << 9) > UINT_MAX);
>>> +
>>> +             payload->range[i].src = src_sects;
>>> +             payload->range[i].len = len;
>>> +     }
>>> +
>>> +     /* storing # of source ranges */
>>> +     payload->copy_range = i;
>>> +     /* storing copy len so far */
>>> +     payload->copy_size = total_len;
>>
>> The comments here make the code ugly. Rename the variables and structure fields
>> to have something self explanatory.
>>
> 
> Agreed.
> 
>>> +
>>> +     *payload_p = payload;
>>> +     return 0;
>>> +err:
>>> +     kfree(payload);
>>> +     return ret;
>>> +}
>>> +
>>> +/**
>>> + * blkdev_issue_copy - queue a copy
>>> + * @bdev:       source block device
>>> + * @nr_srcs: number of source ranges to copy
>>> + * @rlist:   array of source ranges (in bytes)
>>> + * @dest_bdev:       destination block device
>>> + * @dest:    destination (in bytes)
>>> + * @gfp_mask:   memory allocation flags (for bio_alloc)
>>> + *
>>> + * Description:
>>> + *   Copy array of source ranges from source block device to
>>> + *   destination block devcie.
>>> + */
>>> +
>>> +
>>> +int blkdev_issue_copy(struct block_device *bdev, int nr_srcs,
>>> +             struct range_entry *src_rlist, struct block_device *dest_bdev,
>>> +             sector_t dest, gfp_t gfp_mask)
>>> +{
>>> +     struct request_queue *q = bdev_get_queue(bdev);
>>> +     struct blk_copy_payload *payload;
>>> +     sector_t bs_mask, dest_sect;
>>> +     void *buf = NULL;
>>> +     int ret;
>>> +
>>> +     ret = blk_prepare_payload(bdev, nr_srcs, src_rlist, gfp_mask, &payload);
>>> +     if (ret)
>>> +             return ret;
>>> +
>>> +     bs_mask = (bdev_logical_block_size(dest_bdev) >> 9) - 1;
>>> +     if (dest & bs_mask) {
>>> +             return -EINVAL;
>>> +             goto out;
>>> +     }
>>> +     dest_sect = dest >> SECTOR_SHIFT;
>>
>> dest should already be a 512B sector as all block layer functions interface use
>> this unit. What is this doing ?
>>
> 
> As source ranges and length received were in bytes, to keep things
> same, dest was
> also chosen to be in bytes. Seems wrong. Will change it to the 512B sector.

Using a byte interface seems very dangerous since writes can only be at best LBA
sized, and must be physical sector size aligned for zoned block devices. I
strobgly suggest that the interface use sector_t 512B unit.

> 
>>
>>> +
>>> +     if (bdev == dest_bdev && q->limits.copy_offload) {
>>> +             ret = blk_copy_offload(bdev, payload, dest_sect, gfp_mask);
>>> +             if (ret)
>>> +                     goto out;
>>> +     } else {
>>> +             ret = blk_read_to_buf(bdev, payload, gfp_mask, &buf);
>>> +             if (ret)
>>> +                     goto out;
>>> +             ret = blk_write_from_buf(dest_bdev, buf, dest_sect,
>>> +                             payload->copy_size << SECTOR_SHIFT, gfp_mask);
>>
>> Arg... This is really not pretty. At the very least, this should all be in a
>> blk_copy_emulate() helper or something named like that.
>>
> 
> Okay. Will move this to a helper.
> 
>> My worry though is that this likely slow for large copies, not to mention that
>> buf is likely to fail to allocate for large copy cases. As commented previously,
>> dm-kcopyd already does such copy well, with a read-write streaming pipeline and
>> zone support too for the write side. This should really be reused, at least
>> partly, instead of re-implementing this read-write here.
>>
> 
> I was a bit hesitant to use dm layer code in the block layer. It makes sense to
> reuse the code as much as possible. Will try to reuse dm-kcopyd code for copy
> emulation part.

You missed my point. I never suggested that you use DM code in the block layer.
That would be wrong. What I suggested is that you move the dm-kcopyd code from
DM into the block layer, changing the function names to blk_copy_xxx(). See the
current interface in include/linux/dm-kcopyd.h: there is absolutely nothing that
is DM specific in there, so moving that code into block/blk-copy.c should be
straightforward, mostly.

The way I see it, your series should look something like this:
1) A prep patch that moves dm-kcopyd to the block layer, changing the API names
and converting all DM driver users to the new API. This may be a very large
patch though, so splitting it into multiple peaces may be required to facilitate
review.
2) A prep patch that introduces queue flags for devices to advertize their
support for simple copy and a generic api for simple copy BIOs
3) A patch that adds the use of simple copy BIO into the moved dm-kcopyd code
4) The NVMe driver bits that probably will look like what you have now

With this, all DM drivers that currently use dm-kcopyd (RAID and dm-zoned at
least) will get free offload using simple copy commands for sector copies within
the same device. All other copy cases will still work as per kcopyd code. That
is very neat I think.

And you can add one more patch that use this generic copy block interface to
implement copy_file_range for raw block devices as Darrick suggested.


[...]
>>> +static ssize_t queue_copy_offload_store(struct request_queue *q,
>>> +                                    const char *page, size_t count)
>>> +{
>>> +     unsigned long copy_offload;
>>> +     ssize_t ret = queue_var_store(&copy_offload, page, count);
>>> +
>>> +     if (ret < 0)
>>> +             return ret;
>>> +
>>> +     if (copy_offload < 0 || copy_offload > 1)
>>
>> err... "copy_offload != 1" ?
> 
> Initial thought was to keep it either 0 or 1.  I'll change it to 0 or else.

If you use 0 and 1, then make copy_offload a bool. That is more natural given
the variable name.

[...]
>>> +static int blk_ioctl_copy(struct block_device *bdev, fmode_t mode,
>>> +             unsigned long arg)
>>> +{
>>> +     struct copy_range crange;
>>> +     struct range_entry *rlist;
>>> +     struct request_queue *q = bdev_get_queue(bdev);
>>> +     sector_t dest;
>>> +     int ret;
>>> +
>>> +     if (!(mode & FMODE_WRITE))
>>> +             return -EBADF;
>>> +
>>> +     if (!blk_queue_copy(q))
>>> +             return -EOPNOTSUPP;
>>
>> But you added the read-write emulation. So what is the point here ? This ioctl
>> should work for any device, with or without simple copy support. Did you test that ?
>>
> 
> Sorry. It was a mistake. Will fix this.

Please make sure to test to catch such mistakes before sending. It does sound
like your read-write manual copy has not been tested.


-- 
Damien Le Moal
Western Digital Research


From kbusch at kernel.org  Tue Jan  5 18:52:10 2021
From: kbusch at kernel.org (Keith Busch)
Date: Tue, 5 Jan 2021 15:52:10 -0800
Subject: [PATCH 1/2] nvme: support fused nvme requests
In-Reply-To: <20210105224939.1336-2-clay.mayers@kioxia.com>
References: <20210105224939.1336-1-clay.mayers@kioxia.com>
 <20210105224939.1336-2-clay.mayers@kioxia.com>
Message-ID: <20210105235210.GA1278592@dhcp-10-100-145-180.wdc.com>

On Tue, Jan 05, 2021 at 02:49:38PM -0800, klayph at gmail.com wrote:
> @@ -157,6 +157,8 @@ struct nvme_request {
>  	u8			flags;
>  	u16			status;
>  	struct nvme_ctrl	*ctrl;
> +	struct nvme_request	*nrq2;	/* Points to second fused request */
> +	struct nvme_command	cmnd;	/* Saved fused first cmnd */

This struct is getting a bit large, and we allocate 1000's of them. An
extra 72B (3x its current size) for something that likely never gets
used (and can't be used for fabrics) seems a bit much.

> @@ -918,7 +942,13 @@ static blk_status_t nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
>  	}
>  
>  	blk_mq_start_request(req);
> -	nvme_submit_cmd(nvmeq, &cmnd, bd->last);
> +
> +	if (cmnd.common.flags & NVME_CMD_FUSE_FIRST)
> +		memcpy(&nvme_req(req)->nrq2->cmnd, &cmnd, sizeof(cmnd));
> +	else if (cmnd.common.flags & NVME_CMD_FUSE_SECOND)
> +		nvme_submit_cmd2(nvmeq, &nvme_req(req)->cmnd, &cmnd, bd->last);
> +	else
> +		nvme_submit_cmd(nvmeq, &cmnd, bd->last);

There's an unlikely scenario where this breaks down, but it'd look
something like this: the FUSE_FIRST is submitted to the driver, then
before the FUSE_SECOND reaches the driver, the controller is reset.
Because you're only using this through the passthrough interface where
the FAILFAST flag is set, the FUSE_FIRST command is ended in failure,
which releases the command ID for reuse. Once the controller is
restarted, the FUSE_SECOND is dispatched to the driver using an invalid
command ID stored in its 'cmnd' field.


From james.smart at broadcom.com  Tue Jan  5 19:35:33 2021
From: james.smart at broadcom.com (James Smart)
Date: Tue, 5 Jan 2021 16:35:33 -0800
Subject: [PATCH 1/2] nvme: support fused nvme requests
In-Reply-To: <20210105224939.1336-2-clay.mayers@kioxia.com>
References: <20210105224939.1336-1-clay.mayers@kioxia.com>
 <20210105224939.1336-2-clay.mayers@kioxia.com>
Message-ID: <fb7227df-6250-1198-57c3-d57bdcb60a79@broadcom.com>



On 1/5/2021 2:49 PM, klayph at gmail.com wrote:
> From

>   
>   /*
> diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
> index 3be352403839..c24729e100bc 100644
> --- a/drivers/nvme/host/pci.c
> +++ b/drivers/nvme/host/pci.c
> @@ -491,6 +491,30 @@ static inline void nvme_write_sq_db(struct nvme_queue *nvmeq, bool write_sq)
>   	nvmeq->last_sq_tail = nvmeq->sq_tail;
>   }
>   
> +/**
> + * nvme_submit_cmd2() - Copy fused commands into a queue and ring the doorbell
> + * @nvmeq: The queue to use
> + * @cmd: The first command to send
> + * @cmd2: the second command to send
> + * @write_sq: whether to write to the SQ doorbell
> + */
> +static void nvme_submit_cmd2(struct nvme_queue *nvmeq, struct nvme_command *cmd,
> +			     struct nvme_command *cmd2, bool write_sq)
> +{
> +	spin_lock(&nvmeq->sq_lock);
> +	memcpy(nvmeq->sq_cmds + (nvmeq->sq_tail << nvmeq->sqes),
> +		cmd, sizeof(*cmd));
> +	if (++nvmeq->sq_tail == nvmeq->q_depth)
> +		nvmeq->sq_tail = 0;
> +	memcpy(nvmeq->sq_cmds + (nvmeq->sq_tail << nvmeq->sqes),
> +		cmd2, sizeof(*cmd2));
> +	if (++nvmeq->sq_tail == nvmeq->q_depth)
> +		nvmeq->sq_tail = 0;
> +	nvme_write_sq_db(nvmeq, write_sq);
> +	spin_unlock(&nvmeq->sq_lock);
> +}
> +
> +
>   /**
>    * nvme_submit_cmd() - Copy a command into a queue and ring the doorbell
>    * @nvmeq: The queue to use
> @@ -918,7 +942,13 @@ static blk_status_t nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
>   	}
>   
>   	blk_mq_start_request(req);
> -	nvme_submit_cmd(nvmeq, &cmnd, bd->last);
> +
> +	if (cmnd.common.flags & NVME_CMD_FUSE_FIRST)
> +		memcpy(&nvme_req(req)->nrq2->cmnd, &cmnd, sizeof(cmnd));
> +	else if (cmnd.common.flags & NVME_CMD_FUSE_SECOND)
> +		nvme_submit_cmd2(nvmeq, &nvme_req(req)->cmnd, &cmnd, bd->last);
> +	else
> +		nvme_submit_cmd(nvmeq, &cmnd, bd->last);
>   	return BLK_STS_OK;
>   out_unmap_data:
>   	nvme_unmap_data(dev, req);

I think Keith caught the most concerning issue. I've been thinking of 
others but they mostly seem to work.? I assume recopies of the first 
fused cmd to the data structure don't hurt.? I would expect there to be 
a couple of other odd issues if the two requests start working 
independently.

This is the pci transport only. You should either put something in to 
not allow the ioctl on a non-pci transport, or add the support (or 
rejection) to the fabric transports as well.

-- james




-- 
This electronic communication and the information and any files transmitted 
with it, or attached to it, are confidential and are intended solely for 
the use of the individual or entity to whom it is addressed and may contain 
information that is confidential, legally privileged, protected by privacy 
laws, or otherwise restricted from disclosure to anyone else. If you are 
not the intended recipient or the person responsible for delivering the 
e-mail to the intended recipient, you are hereby notified that any use, 
copying, distributing, dissemination, forwarding, printing, or copying of 
this e-mail is strictly prohibited. If you received this e-mail in error, 
please return the e-mail to the sender, delete it from your computer, and 
destroy any printed copy of it.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 4163 bytes
Desc: S/MIME Cryptographic Signature
URL: <http://lists.infradead.org/pipermail/linux-nvme/attachments/20210105/da6c8bc5/attachment.p7s>

From sagi at grimberg.me  Tue Jan  5 20:53:51 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Tue, 5 Jan 2021 17:53:51 -0800
Subject: Data corruption when using multiple devices with NVMEoF TCP
In-Reply-To: <CAJS6Edgb+yCW5q5dA=MEkL0eYs4MXoopdiz72nhkxpkd5Fe_cA@mail.gmail.com>
References: <CAJS6EdjsTVgs3JK3q2DePjEz1A0s9RJTOwqo=Ka7kinNMECtJw@mail.gmail.com>
 <2c0ff5ec-4ae2-ad29-67fb-4744514dab47@grimberg.me>
 <CAJS6Edh8aVAHhKRGqU+7v5C3KY7YxczVg_7Q8QrPGtyvVw7K3w@mail.gmail.com>
 <fd4541e4-78c5-ec3b-b272-467fd11f7472@grimberg.me>
 <20201223084332.GA30502@infradead.org>
 <CAJS6EdijX6ws_wHxygdpcYGtB6JFwLDbDE3A0t0QUYS-LbRakg@mail.gmail.com>
 <16d876c1-524a-38d3-3cff-99ec694464b2@grimberg.me>
 <CAJS6EdivEF0c=3FmKj4wGZoVRKbUvjH_qJLXmO7Tvwsp+km0rw@mail.gmail.com>
 <f631893c-5ce9-95fd-c32c-35a7e70d093c@grimberg.me>
 <CAJS6EdjUAb77-rWd=XmFhsM2_3Hds6VV6jQUVPJoJQHhk12J_Q@mail.gmail.com>
 <a6564a08-a3b0-5c22-51e3-712c4714bcc5@grimberg.me>
 <CAJS6Edgb+yCW5q5dA=MEkL0eYs4MXoopdiz72nhkxpkd5Fe_cA@mail.gmail.com>
Message-ID: <ae5b1654-e580-88be-0498-0cd111b53fa2@grimberg.me>

Hey Hao,

> Okay, will do that in a few days. Something else just popped up and I 
> have a limited time window to use some machines.
> 
> BTW, what is the performance implication of disabling merge? My usage 
> pattern is mostly sequential read and write, and write bandwidth is 
> pretty high.

Did you get a chance to look into this?


From lengchao at huawei.com  Tue Jan  5 21:29:57 2021
From: lengchao at huawei.com (Chao Leng)
Date: Wed, 6 Jan 2021 10:29:57 +0800
Subject: [PATCH 1/6] blk-mq: introduce blk_mq_set_request_complete
In-Reply-To: <20210105191638.GB4426@localhost.localdomain>
References: <20210105071936.25097-1-lengchao@huawei.com>
 <20210105071936.25097-2-lengchao@huawei.com>
 <20210105191638.GB4426@localhost.localdomain>
Message-ID: <e4308bf9-ac47-d765-fe9a-6852a67da5c5@huawei.com>



On 2021/1/6 3:16, Minwoo Im wrote:
> Hello,
> 
> On 21-01-05 15:19:31, Chao Leng wrote:
>> In some scenarios, nvme need setting the state of request to
>> MQ_RQ_COMPLETE. So add an inline function blk_mq_set_request_complete.
>> For details, see the subsequent patches.
>>
>> Signed-off-by: Chao Leng <lengchao at huawei.com>
>> ---
>>   include/linux/blk-mq.h | 5 +++++
>>   1 file changed, 5 insertions(+)
>>
>> diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h
>> index e7482e6ad3ec..cee72d31054d 100644
>> --- a/include/linux/blk-mq.h
>> +++ b/include/linux/blk-mq.h
>> @@ -493,6 +493,11 @@ static inline int blk_mq_request_completed(struct request *rq)
>>   	return blk_mq_rq_state(rq) == MQ_RQ_COMPLETE;
>>   }
>>   
>> +static inline void blk_mq_set_request_complete(struct request *rq)
>> +{
>> +	WRITE_ONCE(rq->state, MQ_RQ_COMPLETE);
>> +}
>> +
> 
> Maybe we can have this newly added helper with updating caller
> in blk_mq_complete_request_remote() also ?
There are similar optimizations for blk_mq_request_started and
blk_mq_request_completed. It may be better to optimize it by using
independent patches.
> 
> Thanks,
> .
> 


From lengchao at huawei.com  Tue Jan  5 21:31:59 2021
From: lengchao at huawei.com (Chao Leng)
Date: Wed, 6 Jan 2021 10:31:59 +0800
Subject: [PATCH 2/6] nvme-core: introduce complete failed request
In-Reply-To: <20210105191154.GA4426@localhost.localdomain>
References: <20210105071936.25097-1-lengchao@huawei.com>
 <20210105071936.25097-3-lengchao@huawei.com>
 <20210105191154.GA4426@localhost.localdomain>
Message-ID: <9f760de9-fc05-a831-9258-cdf15d9ecf90@huawei.com>



On 2021/1/6 3:11, Minwoo Im wrote:
> Hello,
> 
> On 21-01-05 15:19:32, Chao Leng wrote:
>> When a request is queued failed, if the fail status is not
>> BLK_STS_RESOURCE, BLK_STS_DEV_RESOURCE, BLK_STS_ZONE_RESOURCE,
>> the request is need to complete with nvme_complete_rq in queue_rq.
>> So introduce nvme_try_complete_failed_req.
>> The request is needed to complete with NVME_SC_HOST_PATH_ERROR in
>> nvmf_fail_nonready_command and queue_rq.
>> So introduce nvme_complete_failed_req.
>> For details, see the subsequent patches.
>>
>> Signed-off-by: Chao Leng <lengchao at huawei.com>
>> ---
>>   drivers/nvme/host/nvme.h | 18 ++++++++++++++++++
>>   1 file changed, 18 insertions(+)
>>
>> diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
>> index bfcedfa4b057..1a0bddb9158f 100644
>> --- a/drivers/nvme/host/nvme.h
>> +++ b/drivers/nvme/host/nvme.h
>> @@ -649,6 +649,24 @@ void nvme_put_ns_from_disk(struct nvme_ns_head *head, int idx);
>>   extern const struct attribute_group *nvme_ns_id_attr_groups[];
>>   extern const struct block_device_operations nvme_ns_head_ops;
>>   
>> +static inline void nvme_complete_failed_req(struct request *req)
>> +{
>> +	nvme_req(req)->status = NVME_SC_HOST_PATH_ERROR;
>> +	blk_mq_set_request_complete(req);
>> +	nvme_complete_rq(req);
>> +}
>> +
>> +static inline blk_status_t nvme_try_complete_failed_req(struct request *req,
>> +							blk_status_t ret)
>> +{
>> +	if (ret == BLK_STS_RESOURCE || ret == BLK_STS_DEV_RESOURCE ||
>> +	    ret == BLK_STS_ZONE_RESOURCE)
>> +		return ret;
> 
> If it has nothing to do with various conditions, can we have this if
> to switch just like the other function in the same file does:
ok.
> 
> 	switch (ret) {
> 	case BLK_STS_RESOURCE:
> 	case BLK_STS_DEV_RESOURCE:
> 	case BLK_STS_ZONE_RESOURCE:
> 		return ret;
> 	default:
> 		nvme_complete_failed_req(req);
> 		return BLK_STS_OK;
> 	}
> 
>> +
>> +	nvme_complete_failed_req(req);
>> +	return BLK_STS_OK;
>> +}
>> +
> 
> Can we have these two functions along side with nvme_try_complete_req()
> by moving declaration of nvme_coplete_rq() a little bit up ?
This may cause the function declaration disordered.
> 
>>   #ifdef CONFIG_NVME_MULTIPATH
>>   static inline bool nvme_ctrl_use_ana(struct nvme_ctrl *ctrl)
>>   {
>> -- 
>> 2.16.4
>>
> 
> Thanks,
> .
> 


From lengchao at huawei.com  Wed Jan  6 01:36:35 2021
From: lengchao at huawei.com (Chao Leng)
Date: Wed, 6 Jan 2021 14:36:35 +0800
Subject: [PATCH] nvme-rdma: avoid repeated request completion for concurrent
 nvme_rdma_timeout
Message-ID: <20210106063635.7452-1-lengchao@huawei.com>

A crash happens when inject completing request long time(nearly 30s).
Each name space has a request queue, when inject completing request long
time, multi request queues may has time out requests at the same time,
nvme_rdma_timeout will execute concurrently. Multi requests in different
request queues may be queued in the same rdma queue, multi
nvme_rdma_timeout may call nvme_rdma_stop_queue at the same time.
The first nvme_rdma_timeout will clear NVME_RDMA_Q_LIVE and continue
stopping the rdma queue(drain qp), but the others check NVME_RDMA_Q_LIVE
is already cleared, and then directly complete the requests, but the
rdma queue may be not stopped and the request may be already completed
in qp and wait treated, the request will be repeated completed.
Add a multex lock to serialize nvme_rdma_stop_queue.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 drivers/nvme/host/rdma.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index df9f6f4549f1..d5c66e3eeb4a 100644
--- a/drivers/nvme/host/rdma.c
+++ b/drivers/nvme/host/rdma.c
@@ -97,6 +97,7 @@ struct nvme_rdma_queue {
 	struct completion	cm_done;
 	bool			pi_support;
 	int			cq_size;
+	struct mutex		queue_lock;
 };
 
 struct nvme_rdma_ctrl {
@@ -579,6 +580,7 @@ static int nvme_rdma_alloc_queue(struct nvme_rdma_ctrl *ctrl,
 	int ret;
 
 	queue = &ctrl->queues[idx];
+	mutex_init(&queue->queue_lock);
 	queue->ctrl = ctrl;
 	if (idx && ctrl->ctrl.max_integrity_segments)
 		queue->pi_support = true;
@@ -598,7 +600,8 @@ static int nvme_rdma_alloc_queue(struct nvme_rdma_ctrl *ctrl,
 	if (IS_ERR(queue->cm_id)) {
 		dev_info(ctrl->ctrl.device,
 			"failed to create CM ID: %ld\n", PTR_ERR(queue->cm_id));
-		return PTR_ERR(queue->cm_id);
+		ret = PTR_ERR(queue->cm_id);
+		goto out_destroy_mutex;
 	}
 
 	if (ctrl->ctrl.opts->mask & NVMF_OPT_HOST_TRADDR)
@@ -628,6 +631,8 @@ static int nvme_rdma_alloc_queue(struct nvme_rdma_ctrl *ctrl,
 out_destroy_cm_id:
 	rdma_destroy_id(queue->cm_id);
 	nvme_rdma_destroy_queue_ib(queue);
+out_destroy_mutex:
+	mutex_destroy(&queue->queue_lock);
 	return ret;
 }
 
@@ -639,9 +644,10 @@ static void __nvme_rdma_stop_queue(struct nvme_rdma_queue *queue)
 
 static void nvme_rdma_stop_queue(struct nvme_rdma_queue *queue)
 {
-	if (!test_and_clear_bit(NVME_RDMA_Q_LIVE, &queue->flags))
-		return;
-	__nvme_rdma_stop_queue(queue);
+	mutex_lock(&queue->queue_lock);
+	if (test_and_clear_bit(NVME_RDMA_Q_LIVE, &queue->flags))
+		__nvme_rdma_stop_queue(queue);
+	mutex_unlock(&queue->queue_lock);
 }
 
 static void nvme_rdma_free_queue(struct nvme_rdma_queue *queue)
@@ -649,6 +655,7 @@ static void nvme_rdma_free_queue(struct nvme_rdma_queue *queue)
 	if (!test_and_clear_bit(NVME_RDMA_Q_ALLOCATED, &queue->flags))
 		return;
 
+	mutex_destroy(&queue->queue_lock);
 	nvme_rdma_destroy_queue_ib(queue);
 	rdma_destroy_id(queue->cm_id);
 }
-- 
2.16.4



From hch at lst.de  Wed Jan  6 02:59:12 2021
From: hch at lst.de (Christoph Hellwig)
Date: Wed, 6 Jan 2021 08:59:12 +0100
Subject: [PATCH 1/2] nvme: support fused nvme requests
In-Reply-To: <20210105224939.1336-2-clay.mayers@kioxia.com>
References: <20210105224939.1336-1-clay.mayers@kioxia.com>
 <20210105224939.1336-2-clay.mayers@kioxia.com>
Message-ID: <20210106075912.GA31712@lst.de>

I really don't like this.  There is no good use case and it really
affects the I/O submission fast path.


From pkuwangh at gmail.com  Wed Jan  6 03:21:04 2021
From: pkuwangh at gmail.com (Hao Wang)
Date: Wed, 6 Jan 2021 00:21:04 -0800
Subject: Data corruption when using multiple devices with NVMEoF TCP
In-Reply-To: <ae5b1654-e580-88be-0498-0cd111b53fa2@grimberg.me>
References: <CAJS6EdjsTVgs3JK3q2DePjEz1A0s9RJTOwqo=Ka7kinNMECtJw@mail.gmail.com>
 <2c0ff5ec-4ae2-ad29-67fb-4744514dab47@grimberg.me>
 <CAJS6Edh8aVAHhKRGqU+7v5C3KY7YxczVg_7Q8QrPGtyvVw7K3w@mail.gmail.com>
 <fd4541e4-78c5-ec3b-b272-467fd11f7472@grimberg.me>
 <20201223084332.GA30502@infradead.org>
 <CAJS6EdijX6ws_wHxygdpcYGtB6JFwLDbDE3A0t0QUYS-LbRakg@mail.gmail.com>
 <16d876c1-524a-38d3-3cff-99ec694464b2@grimberg.me>
 <CAJS6EdivEF0c=3FmKj4wGZoVRKbUvjH_qJLXmO7Tvwsp+km0rw@mail.gmail.com>
 <f631893c-5ce9-95fd-c32c-35a7e70d093c@grimberg.me>
 <CAJS6EdjUAb77-rWd=XmFhsM2_3Hds6VV6jQUVPJoJQHhk12J_Q@mail.gmail.com>
 <a6564a08-a3b0-5c22-51e3-712c4714bcc5@grimberg.me>
 <CAJS6Edgb+yCW5q5dA=MEkL0eYs4MXoopdiz72nhkxpkd5Fe_cA@mail.gmail.com>
 <ae5b1654-e580-88be-0498-0cd111b53fa2@grimberg.me>
Message-ID: <CAJS6EdhbhqEOSzHLhC-hs0Uj9gTOGV+PwKuR4+z44cx_MwwOoA@mail.gmail.com>

Plan to get to this over the coming weekend. Sorry for the delay.


On Tue, Jan 5, 2021 at 5:53 PM Sagi Grimberg <sagi at grimberg.me> wrote:
>
> Hey Hao,
>
> > Okay, will do that in a few days. Something else just popped up and I
> > have a limited time window to use some machines.
> >
> > BTW, what is the performance implication of disabling merge? My usage
> > pattern is mostly sequential read and write, and write bandwidth is
> > pretty high.
>
> Did you get a chance to look into this?


From hch at lst.de  Wed Jan  6 04:00:53 2021
From: hch at lst.de (Christoph Hellwig)
Date: Wed, 6 Jan 2021 10:00:53 +0100
Subject: [PATCH] nvme: trace: parse format nvm command in detail
In-Reply-To: <20210104160220.GB1024941@dhcp-10-100-145-180.wdc.com>
References: <20210104155343.GA26034@michal-desk>
 <20210104160220.GB1024941@dhcp-10-100-145-180.wdc.com>
Message-ID: <20210106090053.GA32643@lst.de>

On Mon, Jan 04, 2021 at 08:02:20AM -0800, Keith Busch wrote:
> Perhaps it's too late since we've already gone done this path in the
> driver, but IMO, we should have only traced raw dwords without any
> additional decoding. This would have allowed consistent output for all
> kernel versions and resilient to future spec changes. Then that could
> have made possible for a user space utility to do the decoding to a
> human friendly format, kind of like what blkparse does for block layer
> trace events.

the block tracepoints actually contain pretty detailed decoding as well.


From hch at lst.de  Wed Jan  6 04:31:13 2021
From: hch at lst.de (Christoph Hellwig)
Date: Wed, 6 Jan 2021 10:31:13 +0100
Subject: [PATCH] nvmet-rdma: Fix list_del corruption on queue
 establishment failure
In-Reply-To: <1609836414-44997-1-git-send-email-israelr@nvidia.com>
References: <1609836414-44997-1-git-send-email-israelr@nvidia.com>
Message-ID: <20210106093113.GA761@lst.de>

Thanks,

applied to nvme-5.11.


From hch at lst.de  Wed Jan  6 04:31:22 2021
From: hch at lst.de (Christoph Hellwig)
Date: Wed, 6 Jan 2021 10:31:22 +0100
Subject: [PATCH 1/1] nvme: remove the unused status argument from
 nvme_trace_bio_complete
In-Reply-To: <20210105103402.3121-1-mgurtovoy@nvidia.com>
References: <20210105103402.3121-1-mgurtovoy@nvidia.com>
Message-ID: <20210106093122.GB761@lst.de>

Thanks,

applied to nvme-5.11.


From Amit.Engel at Dell.com  Wed Jan  6 05:37:12 2021
From: Amit.Engel at Dell.com (Engel, Amit)
Date: Wed, 6 Jan 2021 10:37:12 +0000
Subject: fabrics connect cmd with a non-zero reserved value
Message-ID: <SN6PR1901MB202957C808A7D493E252D873EED00@SN6PR1901MB2029.namprd19.prod.outlook.com>

Hello, 
We see that when executing nvme connect cmd (Opcode: 0x7f Fabric Cmd)
The host is submitting the cmd with reserved filed set to non-zero value - which is out of spec.
Seems like this issue is not only for connect but also for other fabrics cmds.

Here is a packet capture for nvme connect :

    NVM Express Fabrics (Cmd)
        Opcode: 0x7f Fabric Cmd
        [Fabric Cqe in: 302]
        Reserved: 0x40
        Command ID: 0x0000
        Fabric Cmd Type: Connect (0x01)
        Reserved: 00000000000000000000000000000000000000
        SGL1
        Record Format: 0x0000
        Queue ID: 0x0000
        SQ Size: 0x001f
        Connect Attributes: 0x00
        Reserved: 00
        Keep Alive Timeout: 15000ms
        Reserved: 000000000000000000000000
    Data
        Host Identifier: f1aa9784-195b-4814-893d-44f90a6a92d9
        Controller ID: 0xffff
        Reserved: 000000000000000000000000000000000000000000000000000000000000000000000000...
        Subsystem NQN: nqn.2015-10.com.dell:dellemc-powerstore-23b5145591975EDFF2FE
        Host NQN: nqn.2014-08.org.nvmexpress:uuid:nc5199007
        Reserved: 000000000000000000000000000000000000000000000000000000000000000000000000...

0x40 value is corresponding to PSDT, in a normal (non-fabric) nvme cmd, PSDT field exists.
Do we expect for the same for fabric cmd?
If so, the spec can't mark the second byte of connect cmd as reserved.
Based on nvme spec:
"A reserved bit, byte, word, field, or register shall be cleared to 0h, or in accordance with a future extension to this specification"

Is this a real bug or a spec bug?

Thanks
Amit



From klayph at gmail.com  Wed Jan  6 09:55:58 2021
From: klayph at gmail.com (Clay Mayers)
Date: Wed, 6 Jan 2021 06:55:58 -0800
Subject: [PATCH 1/2] nvme: support fused nvme requests
In-Reply-To: <20210105235210.GA1278592@dhcp-10-100-145-180.wdc.com>
References: <20210105224939.1336-1-clay.mayers@kioxia.com>
 <20210105224939.1336-2-clay.mayers@kioxia.com>
 <20210105235210.GA1278592@dhcp-10-100-145-180.wdc.com>
Message-ID: <CACyZ+O5TJV+WrdfNbih5vU5qFfZCeWxcMv9Jf3OG4Pq9u63fTQ@mail.gmail.com>

Thanks for the very fast feedback.  I will certainly reduce the memory
hit for non-fused cmds and look into dealing with a controller reset.

On Tue, Jan 5, 2021 at 3:52 PM Keith Busch <kbusch at kernel.org> wrote:
>
> On Tue, Jan 05, 2021 at 02:49:38PM -0800, klayph at gmail.com wrote:
> > @@ -157,6 +157,8 @@ struct nvme_request {
> >       u8                      flags;
> >       u16                     status;
> >       struct nvme_ctrl        *ctrl;
> > +     struct nvme_request     *nrq2;  /* Points to second fused request */
> > +     struct nvme_command     cmnd;   /* Saved fused first cmnd */
>
> This struct is getting a bit large, and we allocate 1000's of them. An
> extra 72B (3x its current size) for something that likely never gets
> used (and can't be used for fabrics) seems a bit much.
>
> > @@ -918,7 +942,13 @@ static blk_status_t nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
> >       }
> >
> >       blk_mq_start_request(req);
> > -     nvme_submit_cmd(nvmeq, &cmnd, bd->last);
> > +
> > +     if (cmnd.common.flags & NVME_CMD_FUSE_FIRST)
> > +             memcpy(&nvme_req(req)->nrq2->cmnd, &cmnd, sizeof(cmnd));
> > +     else if (cmnd.common.flags & NVME_CMD_FUSE_SECOND)
> > +             nvme_submit_cmd2(nvmeq, &nvme_req(req)->cmnd, &cmnd, bd->last);
> > +     else
> > +             nvme_submit_cmd(nvmeq, &cmnd, bd->last);
>
> There's an unlikely scenario where this breaks down, but it'd look
> something like this: the FUSE_FIRST is submitted to the driver, then
> before the FUSE_SECOND reaches the driver, the controller is reset.
> Because you're only using this through the passthrough interface where
> the FAILFAST flag is set, the FUSE_FIRST command is ended in failure,
> which releases the command ID for reuse. Once the controller is
> restarted, the FUSE_SECOND is dispatched to the driver using an invalid
> command ID stored in its 'cmnd' field.


From klayph at gmail.com  Wed Jan  6 10:01:09 2021
From: klayph at gmail.com (Clay Mayers)
Date: Wed, 6 Jan 2021 07:01:09 -0800
Subject: [PATCH 1/2] nvme: support fused nvme requests
In-Reply-To: <fb7227df-6250-1198-57c3-d57bdcb60a79@broadcom.com>
References: <20210105224939.1336-1-clay.mayers@kioxia.com>
 <20210105224939.1336-2-clay.mayers@kioxia.com>
 <fb7227df-6250-1198-57c3-d57bdcb60a79@broadcom.com>
Message-ID: <CACyZ+O6ACJr4fSsbZ=fQ8k0LS_3r+7O7bNDxNnQrRjzL9L_nQg@mail.gmail.com>

Thanks for the very fast feedback.  I will ensure this is pci only for now.

On Tue, Jan 5, 2021 at 4:35 PM James Smart <james.smart at broadcom.com> wrote:
>
>
>
> On 1/5/2021 2:49 PM, klayph at gmail.com wrote:
> > From
>
> >
> >   /*
> > diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
> > index 3be352403839..c24729e100bc 100644
> > --- a/drivers/nvme/host/pci.c
> > +++ b/drivers/nvme/host/pci.c
> > @@ -491,6 +491,30 @@ static inline void nvme_write_sq_db(struct nvme_queue *nvmeq, bool write_sq)
> >       nvmeq->last_sq_tail = nvmeq->sq_tail;
> >   }
> >
> > +/**
> > + * nvme_submit_cmd2() - Copy fused commands into a queue and ring the doorbell
> > + * @nvmeq: The queue to use
> > + * @cmd: The first command to send
> > + * @cmd2: the second command to send
> > + * @write_sq: whether to write to the SQ doorbell
> > + */
> > +static void nvme_submit_cmd2(struct nvme_queue *nvmeq, struct nvme_command *cmd,
> > +                          struct nvme_command *cmd2, bool write_sq)
> > +{
> > +     spin_lock(&nvmeq->sq_lock);
> > +     memcpy(nvmeq->sq_cmds + (nvmeq->sq_tail << nvmeq->sqes),
> > +             cmd, sizeof(*cmd));
> > +     if (++nvmeq->sq_tail == nvmeq->q_depth)
> > +             nvmeq->sq_tail = 0;
> > +     memcpy(nvmeq->sq_cmds + (nvmeq->sq_tail << nvmeq->sqes),
> > +             cmd2, sizeof(*cmd2));
> > +     if (++nvmeq->sq_tail == nvmeq->q_depth)
> > +             nvmeq->sq_tail = 0;
> > +     nvme_write_sq_db(nvmeq, write_sq);
> > +     spin_unlock(&nvmeq->sq_lock);
> > +}
> > +
> > +
> >   /**
> >    * nvme_submit_cmd() - Copy a command into a queue and ring the doorbell
> >    * @nvmeq: The queue to use
> > @@ -918,7 +942,13 @@ static blk_status_t nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
> >       }
> >
> >       blk_mq_start_request(req);
> > -     nvme_submit_cmd(nvmeq, &cmnd, bd->last);
> > +
> > +     if (cmnd.common.flags & NVME_CMD_FUSE_FIRST)
> > +             memcpy(&nvme_req(req)->nrq2->cmnd, &cmnd, sizeof(cmnd));
> > +     else if (cmnd.common.flags & NVME_CMD_FUSE_SECOND)
> > +             nvme_submit_cmd2(nvmeq, &nvme_req(req)->cmnd, &cmnd, bd->last);
> > +     else
> > +             nvme_submit_cmd(nvmeq, &cmnd, bd->last);
> >       return BLK_STS_OK;
> >   out_unmap_data:
> >       nvme_unmap_data(dev, req);
>
> I think Keith caught the most concerning issue. I've been thinking of
> others but they mostly seem to work.  I assume recopies of the first
> fused cmd to the data structure don't hurt.  I would expect there to be
> a couple of other odd issues if the two requests start working
> independently.
>
> This is the pci transport only. You should either put something in to
> not allow the ioctl on a non-pci transport, or add the support (or
> rejection) to the fabric transports as well.
>
> -- james
>
>
>
>
> --
> This electronic communication and the information and any files transmitted
> with it, or attached to it, are confidential and are intended solely for
> the use of the individual or entity to whom it is addressed and may contain
> information that is confidential, legally privileged, protected by privacy
> laws, or otherwise restricted from disclosure to anyone else. If you are
> not the intended recipient or the person responsible for delivering the
> e-mail to the intended recipient, you are hereby notified that any use,
> copying, distributing, dissemination, forwarding, printing, or copying of
> this e-mail is strictly prohibited. If you received this e-mail in error,
> please return the e-mail to the sender, delete it from your computer, and
> destroy any printed copy of it.


From samuel.thibault at ens-lyon.org  Wed Jan  6 15:28:23 2021
From: samuel.thibault at ens-lyon.org (Samuel Thibault)
Date: Wed, 6 Jan 2021 21:28:23 +0100
Subject: Are AER corrected errors worrying?
In-Reply-To: <20210104213648.enkuq5e2o6adbiur@function>
References: <20210101224028.4akud7meibjavvtf@function>
 <20210104184435.GE1024941@dhcp-10-100-145-180.wdc.com>
 <20210104201247.5k47gueib3cw4sfr@function>
 <20210104213648.enkuq5e2o6adbiur@function>
Message-ID: <20210106202823.ehdkno3inlzszqtb@function>

Samuel Thibault, le lun. 04 janv. 2021 22:36:48 +0100, a ecrit:
> Samuel Thibault, le lun. 04 janv. 2021 21:12:47 +0100, a ecrit:
> > Vidya Sagar wrote:
> > > Since this is a laptop, I'm suspecting that ASPM states might have
> > > been enabled which could be causing these errors.
> > 
> > Keith Busch, le lun. 04 janv. 2021 10:44:35 -0800, a ecrit:
> > > Sometimes these types of errors occur from low power settings, so you
> > > can try disabling the automatic management of these (assuming the
> > > hardware supports it). To disable nvme specific power state transitions,
> > > the kernel parameter is "nvme_core.default_ps_max_latency_us=0".
> > 
> > I have tried to add it,
> > 
> > I'll watch in the coming
> > hours/days to see if that avoided the issue.
> 
> I did get one
> 
> Jan  4 22:34:53 begin kernel: [ 7165.207562] pcieport 0000:00:1d.0: AER: Corrected error received: 0000:02:00.0
> Jan  4 22:34:53 begin kernel: [ 7165.213891] nvme 0000:02:00.0: PCIe Bus Error: severity=Corrected, type=Physical Layer, (Receiver ID)
> Jan  4 22:34:53 begin kernel: [ 7165.216949] nvme 0000:02:00.0:   device [15b7:5006] error status/mask=00000001/0000e000
> Jan  4 22:34:53 begin kernel: [ 7165.219995] nvme 0000:02:00.0:    [ 0] RxErr
> 
> > > PCI also has automatic link power savings that you can disable with
> > > parameter "pcie_aspm=off".
> > 
> > I'll try that if I still see errors with the nvme_core parameter.
> 
> I'm on it.

I tried to make the machine only run apt-get update every 10m for 24h.

With pcie_aspm=off, I didn't get any corrected error
Without it I got 39 corrected errors

So that seems very relevant :)

Is there more I can provide to investigate if that can somehow be fixed
in the driver? I guess I can safely use the system with pcie_aspm=off?
(the energy saving seems neglectible)

Samuel


From kbusch at kernel.org  Wed Jan  6 16:48:08 2021
From: kbusch at kernel.org (Keith Busch)
Date: Wed, 6 Jan 2021 13:48:08 -0800
Subject: Are AER corrected errors worrying?
In-Reply-To: <20210106202823.ehdkno3inlzszqtb@function>
References: <20210101224028.4akud7meibjavvtf@function>
 <20210104184435.GE1024941@dhcp-10-100-145-180.wdc.com>
 <20210104201247.5k47gueib3cw4sfr@function>
 <20210104213648.enkuq5e2o6adbiur@function>
 <20210106202823.ehdkno3inlzszqtb@function>
Message-ID: <20210106214808.GA1280721@dhcp-10-100-145-180.wdc.com>

On Wed, Jan 06, 2021 at 09:28:23PM +0100, Samuel Thibault wrote:
> Samuel Thibault, le lun. 04 janv. 2021 22:36:48 +0100, a ecrit:
> > Samuel Thibault, le lun. 04 janv. 2021 21:12:47 +0100, a ecrit:
> > > Vidya Sagar wrote:
> > > > Since this is a laptop, I'm suspecting that ASPM states might have
> > > > been enabled which could be causing these errors.
> > > 
> > > Keith Busch, le lun. 04 janv. 2021 10:44:35 -0800, a ecrit:
> > > > Sometimes these types of errors occur from low power settings, so you
> > > > can try disabling the automatic management of these (assuming the
> > > > hardware supports it). To disable nvme specific power state transitions,
> > > > the kernel parameter is "nvme_core.default_ps_max_latency_us=0".
> > > 
> > > I have tried to add it,
> > > 
> > > I'll watch in the coming
> > > hours/days to see if that avoided the issue.
> > 
> > I did get one
> > 
> > Jan  4 22:34:53 begin kernel: [ 7165.207562] pcieport 0000:00:1d.0: AER: Corrected error received: 0000:02:00.0
> > Jan  4 22:34:53 begin kernel: [ 7165.213891] nvme 0000:02:00.0: PCIe Bus Error: severity=Corrected, type=Physical Layer, (Receiver ID)
> > Jan  4 22:34:53 begin kernel: [ 7165.216949] nvme 0000:02:00.0:   device [15b7:5006] error status/mask=00000001/0000e000
> > Jan  4 22:34:53 begin kernel: [ 7165.219995] nvme 0000:02:00.0:    [ 0] RxErr
> > 
> > > > PCI also has automatic link power savings that you can disable with
> > > > parameter "pcie_aspm=off".
> > > 
> > > I'll try that if I still see errors with the nvme_core parameter.
> > 
> > I'm on it.
> 
> I tried to make the machine only run apt-get update every 10m for 24h.
> 
> With pcie_aspm=off, I didn't get any corrected error
> Without it I got 39 corrected errors
> 
> So that seems very relevant :)
> 
> Is there more I can provide to investigate if that can somehow be fixed
> in the driver? I guess I can safely use the system with pcie_aspm=off?
> (the energy saving seems neglectible)

I don't think there's more to do from the kernel or driver beyond
disabling usage of the problematic feature. I think a proper fix would
have to come from the hardware vendor.


From samuel.thibault at ens-lyon.org  Wed Jan  6 17:40:00 2021
From: samuel.thibault at ens-lyon.org (Samuel Thibault)
Date: Wed, 6 Jan 2021 23:40:00 +0100
Subject: Are AER corrected errors worrying?
In-Reply-To: <20210106214808.GA1280721@dhcp-10-100-145-180.wdc.com>
References: <20210101224028.4akud7meibjavvtf@function>
 <20210104184435.GE1024941@dhcp-10-100-145-180.wdc.com>
 <20210104201247.5k47gueib3cw4sfr@function>
 <20210104213648.enkuq5e2o6adbiur@function>
 <20210106202823.ehdkno3inlzszqtb@function>
 <20210106214808.GA1280721@dhcp-10-100-145-180.wdc.com>
Message-ID: <20210106224000.skryo2aijhfiomfw@function>

Keith Busch, le mer. 06 janv. 2021 13:48:08 -0800, a ecrit:
> On Wed, Jan 06, 2021 at 09:28:23PM +0100, Samuel Thibault wrote:
> > Is there more I can provide to investigate if that can somehow be fixed
> > in the driver? I guess I can safely use the system with pcie_aspm=off?
> > (the energy saving seems neglectible)
> 
> I don't think there's more to do from the kernel or driver beyond
> disabling usage of the problematic feature. I think a proper fix would
> have to come from the hardware vendor.

Ok, thanks!

Samuel


From lengchao at huawei.com  Wed Jan  6 22:31:43 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 7 Jan 2021 11:31:43 +0800
Subject: [PATCH v2 0/6] avoid repeated request completion and IO error
Message-ID: <20210107033149.15701-1-lengchao@huawei.com>

First avoid repeated request completion for nvmf_fail_nonready_command.
Second avoid IO error and repeated request completion for queue_rq.

V2:
	- use "switch" instead "if" to check return status
	
Chao Leng (6):
  blk-mq: introduce blk_mq_set_request_complete
  nvme-core: introduce complete failed request
  nvme-fabrics: avoid repeated request completion for
    nvmf_fail_nonready_command
  nvme-rdma: avoid IO error and repeated request completion
  nvme-tcp: avoid IO error and repeated request completion
  nvme-fc: avoid IO error and repeated request completion

 drivers/nvme/host/fabrics.c |  4 +---
 drivers/nvme/host/fc.c      |  6 ++++--
 drivers/nvme/host/nvme.h    | 21 +++++++++++++++++++++
 drivers/nvme/host/rdma.c    |  2 +-
 drivers/nvme/host/tcp.c     |  2 +-
 include/linux/blk-mq.h      |  5 +++++
 6 files changed, 33 insertions(+), 7 deletions(-)

-- 
2.16.4



From lengchao at huawei.com  Wed Jan  6 22:31:48 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 7 Jan 2021 11:31:48 +0800
Subject: [PATCH v2 5/6] nvme-tcp: avoid IO error and repeated request
 completion
In-Reply-To: <20210107033149.15701-1-lengchao@huawei.com>
References: <20210107033149.15701-1-lengchao@huawei.com>
Message-ID: <20210107033149.15701-6-lengchao@huawei.com>

When a request is queued failed, blk_status_t is directly returned
to the blk-mq. If blk_status_t is not BLK_STS_RESOURCE,
BLK_STS_DEV_RESOURCE, BLK_STS_ZONE_RESOURCE, blk-mq call
blk_mq_end_request to complete the request with BLK_STS_IOERR.
In two scenarios, the request should be retried and may succeed.
First, if work with nvme multipath, the request may be retried
successfully in another path, because the error is probably related to
the path. Second, if work without multipath software, the request may
be retried successfully after error recovery.
If the request is completed with BLK_STS_IOERR in blk_mq_dispatch_rq_list.
The state of request may be changed to MQ_RQ_IN_FLIGHT. If free the
request asynchronously such as in nvme_submit_user_cmd, in extreme
scenario the request will be repeated freed in tear down.
If a non-resource error occurs when queue_rq, should directly call
nvme_complete_rq to complete request and set the state of request to
MQ_RQ_COMPLETE. nvme_complete_rq will decide to retry, fail over or end
the request.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 drivers/nvme/host/tcp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 1ba659927442..a81683ce8cff 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -2306,7 +2306,7 @@ static blk_status_t nvme_tcp_queue_rq(struct blk_mq_hw_ctx *hctx,
 
 	ret = nvme_tcp_setup_cmd_pdu(ns, rq);
 	if (unlikely(ret))
-		return ret;
+		return nvme_try_complete_failed_req(rq, ret);
 
 	blk_mq_start_request(rq);
 
-- 
2.16.4



From lengchao at huawei.com  Wed Jan  6 22:31:47 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 7 Jan 2021 11:31:47 +0800
Subject: [PATCH v2 4/6] nvme-rdma: avoid IO error and repeated request
 completion
In-Reply-To: <20210107033149.15701-1-lengchao@huawei.com>
References: <20210107033149.15701-1-lengchao@huawei.com>
Message-ID: <20210107033149.15701-5-lengchao@huawei.com>

When a request is queued failed, blk_status_t is directly returned
to the blk-mq. If blk_status_t is not BLK_STS_RESOURCE,
BLK_STS_DEV_RESOURCE, BLK_STS_ZONE_RESOURCE, blk-mq call
blk_mq_end_request to complete the request with BLK_STS_IOERR.
In two scenarios, the request should be retried and may succeed.
First, if work with nvme multipath, the request may be retried
successfully in another path, because the error is probably related to
the path. Second, if work without multipath software, the request may
be retried successfully after error recovery.
If the request is complete with BLK_STS_IOERR in blk_mq_dispatch_rq_list.
The state of request may be changed to MQ_RQ_IN_FLIGHT. If free the
request asynchronously such as in nvme_submit_user_cmd, in extreme
scenario the request will be repeated freed in tear down.
If a non-resource error occurs in queue_rq, should directly call
nvme_complete_rq to complete request and set the state of request to
MQ_RQ_COMPLETE. nvme_complete_rq will decide to retry, fail over or end
the request.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 drivers/nvme/host/rdma.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index df9f6f4549f1..4a89bf44ecdc 100644
--- a/drivers/nvme/host/rdma.c
+++ b/drivers/nvme/host/rdma.c
@@ -2093,7 +2093,7 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
 unmap_qe:
 	ib_dma_unmap_single(dev, req->sqe.dma, sizeof(struct nvme_command),
 			    DMA_TO_DEVICE);
-	return ret;
+	return nvme_try_complete_failed_req(rq, ret);
 }
 
 static int nvme_rdma_poll(struct blk_mq_hw_ctx *hctx)
-- 
2.16.4



From lengchao at huawei.com  Wed Jan  6 22:31:45 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 7 Jan 2021 11:31:45 +0800
Subject: [PATCH v2 2/6] nvme-core: introduce complete failed request
In-Reply-To: <20210107033149.15701-1-lengchao@huawei.com>
References: <20210107033149.15701-1-lengchao@huawei.com>
Message-ID: <20210107033149.15701-3-lengchao@huawei.com>

When a request is queued failed, if the fail status is not
BLK_STS_RESOURCE, BLK_STS_DEV_RESOURCE, BLK_STS_ZONE_RESOURCE,
the request is need to complete with nvme_complete_rq in queue_rq.
So introduce nvme_try_complete_failed_req.
The request is needed to complete with NVME_SC_HOST_PATH_ERROR in
nvmf_fail_nonready_command and queue_rq.
So introduce nvme_complete_failed_req.
For details, see the subsequent patches.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 drivers/nvme/host/nvme.h | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index bfcedfa4b057..fc4eefdfbb34 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -649,6 +649,27 @@ void nvme_put_ns_from_disk(struct nvme_ns_head *head, int idx);
 extern const struct attribute_group *nvme_ns_id_attr_groups[];
 extern const struct block_device_operations nvme_ns_head_ops;
 
+static inline void nvme_complete_failed_req(struct request *req)
+{
+	nvme_req(req)->status = NVME_SC_HOST_PATH_ERROR;
+	blk_mq_set_request_complete(req);
+	nvme_complete_rq(req);
+}
+
+static inline blk_status_t nvme_try_complete_failed_req(struct request *req,
+							blk_status_t ret)
+{
+	switch (ret) {
+	case BLK_STS_RESOURCE:
+	case BLK_STS_DEV_RESOURCE:
+	case BLK_STS_ZONE_RESOURCE:
+		return ret;
+	default:
+		nvme_complete_failed_req(req);
+		return BLK_STS_OK;
+	}
+}
+
 #ifdef CONFIG_NVME_MULTIPATH
 static inline bool nvme_ctrl_use_ana(struct nvme_ctrl *ctrl)
 {
-- 
2.16.4



From lengchao at huawei.com  Wed Jan  6 22:31:46 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 7 Jan 2021 11:31:46 +0800
Subject: [PATCH v2 3/6] nvme-fabrics: avoid repeated request completion for
 nvmf_fail_nonready_command
In-Reply-To: <20210107033149.15701-1-lengchao@huawei.com>
References: <20210107033149.15701-1-lengchao@huawei.com>
Message-ID: <20210107033149.15701-4-lengchao@huawei.com>

The request may be completed with NVME_SC_HOST_PATH_ERROR in
nvmf_fail_nonready_command. The state of request will be changed to
MQ_RQ_IN_FLIGHT before call nvme_complete_rq. If free the request
asynchronously such as in nvme_submit_user_cmd, in extreme scenario
the request will be repeated freed in tear down.
Nvmf_fail_nonready_command do not need calling blk_mq_start_request
before complete the request. Nvmf_fail_nonready_command should set
the state of request to MQ_RQ_COMPLETE before complete the request.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 drivers/nvme/host/fabrics.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c
index 72ac00173500..874e4320e214 100644
--- a/drivers/nvme/host/fabrics.c
+++ b/drivers/nvme/host/fabrics.c
@@ -553,9 +553,7 @@ blk_status_t nvmf_fail_nonready_command(struct nvme_ctrl *ctrl,
 	    !blk_noretry_request(rq) && !(rq->cmd_flags & REQ_NVME_MPATH))
 		return BLK_STS_RESOURCE;
 
-	nvme_req(rq)->status = NVME_SC_HOST_PATH_ERROR;
-	blk_mq_start_request(rq);
-	nvme_complete_rq(rq);
+	nvme_complete_failed_req(rq);
 	return BLK_STS_OK;
 }
 EXPORT_SYMBOL_GPL(nvmf_fail_nonready_command);
-- 
2.16.4



From lengchao at huawei.com  Wed Jan  6 22:31:44 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 7 Jan 2021 11:31:44 +0800
Subject: [PATCH v2 1/6] blk-mq: introduce blk_mq_set_request_complete
In-Reply-To: <20210107033149.15701-1-lengchao@huawei.com>
References: <20210107033149.15701-1-lengchao@huawei.com>
Message-ID: <20210107033149.15701-2-lengchao@huawei.com>

In some scenarios, nvme need setting the state of request to
MQ_RQ_COMPLETE. So add an inline function blk_mq_set_request_complete.
For details, see the subsequent patches.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 include/linux/blk-mq.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h
index e7482e6ad3ec..cee72d31054d 100644
--- a/include/linux/blk-mq.h
+++ b/include/linux/blk-mq.h
@@ -493,6 +493,11 @@ static inline int blk_mq_request_completed(struct request *rq)
 	return blk_mq_rq_state(rq) == MQ_RQ_COMPLETE;
 }
 
+static inline void blk_mq_set_request_complete(struct request *rq)
+{
+	WRITE_ONCE(rq->state, MQ_RQ_COMPLETE);
+}
+
 void blk_mq_start_request(struct request *rq);
 void blk_mq_end_request(struct request *rq, blk_status_t error);
 void __blk_mq_end_request(struct request *rq, blk_status_t error);
-- 
2.16.4



From lengchao at huawei.com  Wed Jan  6 22:31:49 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 7 Jan 2021 11:31:49 +0800
Subject: [PATCH v2 6/6] nvme-fc: avoid IO error and repeated request completion
In-Reply-To: <20210107033149.15701-1-lengchao@huawei.com>
References: <20210107033149.15701-1-lengchao@huawei.com>
Message-ID: <20210107033149.15701-7-lengchao@huawei.com>

When a request is queued failed, blk_status_t is directly returned
to the blk-mq. If blk_status_t is not BLK_STS_RESOURCE,
BLK_STS_DEV_RESOURCE, BLK_STS_ZONE_RESOURCE, blk-mq call
blk_mq_end_request to complete the request with BLK_STS_IOERR.
In two scenarios, the request should be retried and may succeed.
First, if work with nvme multipath, the request may be retried
successfully in another path, because the error is probably related to
the path. Second, if work without multipath software, the request may
be retried successfully after error recovery.
If the request is completed with BLK_STS_IOERR in blk_mq_dispatch_rq_list.
The state of request may be changed to MQ_RQ_IN_FLIGHT. If free the
request asynchronously such as in nvme_submit_user_cmd, in extreme
scenario the request will be repeated freed in tear down.
If a non-resource error occurs when queue_rq, should directly call
nvme_complete_rq to complete request and set the state of request to
MQ_RQ_COMPLETE. nvme_complete_rq will decide to retry, fail over or end
the request.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 drivers/nvme/host/fc.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c
index 38373a0e86ef..f6a5758ef1ea 100644
--- a/drivers/nvme/host/fc.c
+++ b/drivers/nvme/host/fc.c
@@ -2761,7 +2761,7 @@ nvme_fc_queue_rq(struct blk_mq_hw_ctx *hctx,
 
 	ret = nvme_setup_cmd(ns, rq, sqe);
 	if (ret)
-		return ret;
+		goto fail;
 
 	/*
 	 * nvme core doesn't quite treat the rq opaquely. Commands such
@@ -2781,7 +2781,9 @@ nvme_fc_queue_rq(struct blk_mq_hw_ctx *hctx,
 	}
 
 
-	return nvme_fc_start_fcp_op(ctrl, queue, op, data_len, io_dir);
+	ret = nvme_fc_start_fcp_op(ctrl, queue, op, data_len, io_dir);
+fail:
+	return nvme_try_complete_failed_req(rq, ret);
 }
 
 static void
-- 
2.16.4



From muneendra.kumar at broadcom.com  Wed Jan  6 17:00:18 2021
From: muneendra.kumar at broadcom.com (Muneendra)
Date: Thu,  7 Jan 2021 03:30:18 +0530
Subject: [PATCH v7 04/16] lpfc: vmid: Add the datastructure for supporting
 VMID in lpfc
In-Reply-To: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
References: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
Message-ID: <1609970430-19084-5-git-send-email-muneendra.kumar@broadcom.com>

From: Gaurav Srivastava <gaurav.srivastava at broadcom.com>

This patch adds the primary datastructures needed to implement VMID in lpfc
driver. It maintains the capability, current state, hash table for the
vmid/appid along with other information.

Signed-off-by: Gaurav Srivastava <gaurav.srivastava at broadcom.com>
Signed-off-by: James Smart <jsmart2021 at gmail.com>

---
v7:
No change

v6:
No change

v5:
No Change

v4:
No change

v3:
No change

v2:
Ported the patch on top of 5.10/scsi-queue
Removed unused variable.
---
 drivers/scsi/lpfc/lpfc.h | 97 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 97 insertions(+)

diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index a54c8da30273..ab61352363d4 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -303,6 +303,63 @@ struct lpfc_stats {
 struct lpfc_hba;
 
 
+#define LPFC_VMID_TIMER   300	/* timer interval in seconds. */
+
+#define LPFC_MAX_VMID_SIZE      256
+#define LPFC_COMPRESS_VMID_SIZE 16
+
+union lpfc_vmid_io_tag {
+	u32 app_id;	/* App Id vmid */
+	u8 cs_ctl_vmid;	/* Priority tag vmid */
+};
+
+#define JIFFIES_PER_HR	(HZ * 60 * 60)
+
+struct lpfc_vmid {
+	u8 flag;
+#define LPFC_VMID_SLOT_FREE     0x0
+#define LPFC_VMID_SLOT_USED     0x1
+#define LPFC_VMID_REQ_REGISTER  0x2
+#define LPFC_VMID_REGISTERED    0x4
+#define LPFC_VMID_DE_REGISTER   0x8
+	u8 host_vmid[LPFC_MAX_VMID_SIZE];
+	union lpfc_vmid_io_tag un;
+	u64 io_rd_cnt;
+	u64 io_wr_cnt;
+	u8 vmid_len;
+	u8 delete_inactive; /* Delete if inactive flag 0 = no, 1 = yes */
+	u32 hash_index;
+	u64 __percpu *last_io_time;
+};
+
+#define lpfc_vmid_is_type_priority_tag(vport)\
+	(vport->vmid_priority_tagging ? 1 : 0)
+
+#define LPFC_VMID_HASH_SIZE     256
+#define LPFC_VMID_HASH_MASK     255
+#define LPFC_VMID_HASH_SHIFT    6
+
+struct lpfc_vmid_context {
+	struct lpfc_vmid *vmp;
+	struct lpfc_nodelist *nlp;
+	u8 instantiated;
+};
+
+struct lpfc_vmid_priority_range {
+	u8 low;
+	u8 high;
+	u8 qos;
+};
+
+struct lpfc_vmid_priority_info {
+	u32 num_descriptors;
+	struct lpfc_vmid_priority_range *vmid_range;
+};
+
+#define QFPA_EVEN_ONLY 0x01
+#define QFPA_ODD_ONLY  0x02
+#define QFPA_EVEN_ODD  0x03
+
 enum discovery_state {
 	LPFC_VPORT_UNKNOWN     =  0,    /* vport state is unknown */
 	LPFC_VPORT_FAILED      =  1,    /* vport has failed */
@@ -442,6 +499,9 @@ struct lpfc_vport {
 #define WORKER_RAMP_DOWN_QUEUE         0x800	/* hba: Decrease Q depth */
 #define WORKER_RAMP_UP_QUEUE           0x1000	/* hba: Increase Q depth */
 #define WORKER_SERVICE_TXQ             0x2000	/* hba: IOCBs on the txq */
+#define WORKER_CHECK_INACTIVE_VMID     0x4000	/* hba: check inactive vmids */
+#define WORKER_CHECK_VMID_ISSUE_QFPA   0x8000	/* vport: Check if qfpa need */
+						/* to issue */
 
 	struct timer_list els_tmofunc;
 	struct timer_list delayed_disc_tmo;
@@ -452,6 +512,8 @@ struct lpfc_vport {
 #define FC_LOADING		0x1	/* HBA in process of loading drvr */
 #define FC_UNLOADING		0x2	/* HBA in process of unloading drvr */
 #define FC_ALLOW_FDMI		0x4	/* port is ready for FDMI requests */
+#define FC_ALLOW_VMID		0x8	/* Allow VMID IO's */
+#define FC_DEREGISTER_ALL_APP_ID	0x10	/* Deregister all vmid's */
 	/* Vport Config Parameters */
 	uint32_t cfg_scan_down;
 	uint32_t cfg_lun_queue_depth;
@@ -470,9 +532,36 @@ struct lpfc_vport {
 	uint32_t cfg_tgt_queue_depth;
 	uint32_t cfg_first_burst_size;
 	uint32_t dev_loss_tmo_changed;
+	/* VMID parameters */
+	u8 lpfc_vmid_host_uuid[LPFC_COMPRESS_VMID_SIZE];
+	u32 max_vmid;	/* maximum VMIDs allowed per port */
+	u32 cur_vmid_cnt;	/* Current VMID count */
+#define LPFC_MIN_VMID	4
+#define LPFC_MAX_VMID	255
+	u32 vmid_inactivity_timeout;	/* Time after which the VMID */
+						/* deregisters from switch */
+	u32 vmid_priority_tagging;
+#define LPFC_VMID_PRIO_TAG_DISABLE	0 /* Disable */
+#define LPFC_VMID_PRIO_TAG_SUP_TARGETS	1 /* Allow supported targets only */
+#define LPFC_VMID_PRIO_TAG_ALL_TARGETS	2 /* Allow all targets */
+	unsigned long *vmid_priority_range;
+#define LPFC_VMID_MAX_PRIORITY_RANGE    256
+#define LPFC_VMID_PRIORITY_BITMAP_SIZE  32
+	u8 vmid_flag;
+#define LPFC_VMID_IN_USE		0x1
+#define LPFC_VMID_ISSUE_QFPA		0x2
+#define LPFC_VMID_QFPA_CMPL		0x4
+#define LPFC_VMID_QOS_ENABLED		0x8
+#define LPFC_VMID_TIMER_ENBLD		0x10
+	struct fc_qfpa_res *qfpa_res;
 
 	struct fc_vport *fc_vport;
 
+	struct lpfc_vmid *vmid;
+	struct lpfc_vmid *hash_table[LPFC_VMID_HASH_SIZE];
+	rwlock_t vmid_lock;
+	struct lpfc_vmid_priority_info vmid_priority;
+
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
 	struct dentry *debug_disc_trc;
 	struct dentry *debug_nodelist;
@@ -934,6 +1023,13 @@ struct lpfc_hba {
 	struct nvmet_fc_target_port *targetport;
 	lpfc_vpd_t vpd;		/* vital product data */
 
+	u32 cfg_max_vmid;	/* maximum VMIDs allowed per port */
+	u32 cfg_vmid_app_header;
+#define LPFC_VMID_APP_HEADER_DISABLE	0
+#define LPFC_VMID_APP_HEADER_ENABLE	1
+	u32 cfg_vmid_priority_tagging;
+	u32 cfg_vmid_inactivity_timeout;	/* Time after which the VMID */
+						/*  deregisters from switch */
 	struct pci_dev *pcidev;
 	struct list_head      work_list;
 	uint32_t              work_ha;      /* Host Attention Bits for WT */
@@ -1175,6 +1271,7 @@ struct lpfc_hba {
 	struct list_head ct_ev_waiters;
 	struct unsol_rcv_ct_ctx ct_ctx[LPFC_CT_CTX_MAX];
 	uint32_t ctx_idx;
+	struct timer_list inactive_vmid_poll;
 
 	/* RAS Support */
 	struct lpfc_ras_fwlog ras_fwlog;
-- 
2.26.2



From muneendra.kumar at broadcom.com  Wed Jan  6 17:00:17 2021
From: muneendra.kumar at broadcom.com (Muneendra)
Date: Thu,  7 Jan 2021 03:30:17 +0530
Subject: [PATCH v7 03/16] nvme: Added a newsysfs attribute appid_store
In-Reply-To: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
References: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
Message-ID: <1609970430-19084-4-git-send-email-muneendra.kumar@broadcom.com>

Added a new sysfs attribute appid_store under
/sys/class/fc/fc_udev_device/*

With this new interface the user can set the application identfier
in  the blkcg associted with cgroup id.

Once the application identifer has set with this interface it allows
identification of traffic sources at an individual cgroup based
Applications (ex:virtual machine (VM))level in both host and
fabric infrastructure(FC).

Below is the interface provided to set the app_id

echo "<cgroupid>:<appid>" >> /sys/class/fc/fc_udev_device/appid_store
echo "457E:100000109b521d27" >> /sys/class/fc/fc_udev_device/appid_store

Signed-off-by: Muneendra <muneendra.kumar at broadcom.com>

---
v7:
No change

v6:
No change

v5:
Replaced APPID_LEN with FC_APPID_LEN

v4:
No change

v3:
Replaced blkcg_set_app_identifier function with blkcg_set_fc_appid

v2:
New Patch
---
 drivers/nvme/host/fc.c | 73 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 72 insertions(+), 1 deletion(-)

diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c
index 3c002bdcace3..ed689ba773b1 100644
--- a/drivers/nvme/host/fc.c
+++ b/drivers/nvme/host/fc.c
@@ -9,7 +9,7 @@
 #include <uapi/scsi/fc/fc_els.h>
 #include <linux/delay.h>
 #include <linux/overflow.h>
-
+#include <linux/blk-cgroup.h>
 #include "nvme.h"
 #include "fabrics.h"
 #include <linux/nvme-fc-driver.h>
@@ -3821,10 +3821,81 @@ static ssize_t nvme_fc_nvme_discovery_store(struct device *dev,
 
 	return count;
 }
+
+/*parse the Cgroup id from a buf and returns the length of cgrpid*/
+static int fc_parse_cgrpid(const char *buf, u64 *id)
+{
+	char cgrp_id[16+1];
+	int cgrpid_len, j;
+
+	memset(cgrp_id, 0x0, sizeof(cgrp_id));
+	for (cgrpid_len = 0, j = 0; cgrpid_len < 17; cgrpid_len++) {
+		if (buf[cgrpid_len] != ':')
+			cgrp_id[cgrpid_len] = buf[cgrpid_len];
+		else {
+			j = 1;
+			break;
+		}
+	}
+	if (!j)
+		return -EINVAL;
+	if (kstrtou64(cgrp_id, 16, id) < 0)
+		return -EINVAL;
+	return cgrpid_len;
+}
+
+/*
+ * fc_update_appid :parses and updates the appid in the blkcg associated with
+ * cgroupid.
+ * @buf: buf contains both cgrpid and appid info
+ * @count: size of the buffer
+ */
+static int fc_update_appid(const char *buf, size_t count)
+{
+	u64 cgrp_id;
+	int appid_len = 0;
+	int cgrpid_len = 0;
+	char app_id[FC_APPID_LEN];
+	int ret = 0;
+
+	if (buf[count-1] == '\n')
+		count--;
+
+	if ((count > (16+1+FC_APPID_LEN)) || (!strchr(buf, ':')))
+		return -EINVAL;
+
+	cgrpid_len = fc_parse_cgrpid(buf, &cgrp_id);
+	if (cgrpid_len < 0)
+		return -EINVAL;
+	/*appid len is count - cgrpid_len -1 (: + \n) */
+	appid_len = count - cgrpid_len - 1;
+	if (appid_len > FC_APPID_LEN)
+		return -EINVAL;
+
+	memset(app_id, 0x0, sizeof(app_id));
+	memcpy(app_id, &buf[cgrpid_len+1], appid_len);
+	ret = blkcg_set_fc_appid(app_id, cgrp_id, sizeof(app_id));
+	if (ret < 0)
+		return ret;
+	return count;
+}
+
+static ssize_t fc_appid_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	int ret  = 0;
+
+	ret = fc_update_appid(buf, count);
+	if (ret < 0)
+		return -EINVAL;
+	return count;
+}
 static DEVICE_ATTR(nvme_discovery, 0200, NULL, nvme_fc_nvme_discovery_store);
+static DEVICE_ATTR(appid_store, 0200, NULL, fc_appid_store);
 
 static struct attribute *nvme_fc_attrs[] = {
 	&dev_attr_nvme_discovery.attr,
+	&dev_attr_appid_store.attr,
 	NULL
 };
 
-- 
2.26.2



From muneendra.kumar at broadcom.com  Wed Jan  6 17:00:15 2021
From: muneendra.kumar at broadcom.com (Muneendra)
Date: Thu,  7 Jan 2021 03:30:15 +0530
Subject: [PATCH v7 01/16] cgroup: Added cgroup_get_from_id
In-Reply-To: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
References: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
Message-ID: <1609970430-19084-2-git-send-email-muneendra.kumar@broadcom.com>

Added a new function cgroup_get_from_id  to retrieve the cgroup
associated with cgroup id.
Exported the same as this can be used by blk-cgorup.c

Added function declaration of cgroup_get_from_id in cgorup.h

This patch also exported the function cgroup_get_e_css
as this is getting used in blk-cgroup.h

Signed-off-by: Muneendra <muneendra.kumar at broadcom.com>

---
v7:
No change

v6:
No change

v5:
renamed the function cgroup_get_from_kernfs_id to
cgroup_get_from_id

v4:
No change

v3:
Exported the cgroup_get_e_css

v2:
New patch
---
 include/linux/cgroup.h |  6 ++++++
 kernel/cgroup/cgroup.c | 26 ++++++++++++++++++++++++++
 2 files changed, 32 insertions(+)

diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 618838c48313..da31b14db198 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -696,6 +696,7 @@ static inline void cgroup_kthread_ready(void)
 }
 
 void cgroup_path_from_kernfs_id(u64 id, char *buf, size_t buflen);
+struct cgroup *cgroup_get_from_id(u64 id);
 #else /* !CONFIG_CGROUPS */
 
 struct cgroup_subsys_state;
@@ -743,6 +744,11 @@ static inline bool task_under_cgroup_hierarchy(struct task_struct *task,
 
 static inline void cgroup_path_from_kernfs_id(u64 id, char *buf, size_t buflen)
 {}
+
+static struct cgroup *cgroup_get_from_id(u64 id)
+{
+	return NULL;
+}
 #endif /* !CONFIG_CGROUPS */
 
 #ifdef CONFIG_CGROUPS
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index e41c21819ba0..34ebfbeba098 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -580,6 +580,7 @@ struct cgroup_subsys_state *cgroup_get_e_css(struct cgroup *cgrp,
 	rcu_read_unlock();
 	return css;
 }
+EXPORT_SYMBOL_GPL(cgroup_get_e_css);
 
 static void cgroup_get_live(struct cgroup *cgrp)
 {
@@ -5805,6 +5806,31 @@ void cgroup_path_from_kernfs_id(u64 id, char *buf, size_t buflen)
 	kernfs_put(kn);
 }
 
+/*
+ * cgroup_get_from_id : get the cgroup associated with cgroup id
+ * @id: cgroup id
+ * On success it returns the cgrp on failure it returns NULL
+ */
+struct cgroup *cgroup_get_from_id(u64 id)
+{
+	struct kernfs_node *kn;
+	struct cgroup *cgrp = NULL;
+
+	mutex_lock(&cgroup_mutex);
+	kn = kernfs_find_and_get_node_by_id(cgrp_dfl_root.kf_root, id);
+	if (!kn)
+		goto out_unlock;
+
+	cgrp = kn->priv;
+	if (cgroup_is_dead(cgrp) || !cgroup_tryget(cgrp))
+		cgrp = NULL;
+	kernfs_put(kn);
+out_unlock:
+	mutex_unlock(&cgroup_mutex);
+	return cgrp;
+}
+EXPORT_SYMBOL_GPL(cgroup_get_from_id);
+
 /*
  * proc_cgroup_show()
  *  - Print task's cgroup paths into seq_file, one line for each hierarchy
-- 
2.26.2



From muneendra.kumar at broadcom.com  Wed Jan  6 17:00:14 2021
From: muneendra.kumar at broadcom.com (Muneendra)
Date: Thu,  7 Jan 2021 03:30:14 +0530
Subject: [PATCH v7 00/16] blkcg:Support to track FC storage blk io traffic
Message-ID: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>

This Patch added a unique application identifier i.e
app_id  knob to  blkcg which allows identification of traffic
sources at an individual cgroup based Applications
(ex:virtual machine (VM))level in both host and
fabric infrastructure.

Added a new sysfs attribute appid_store to set the application identfier
in  the blkcg associted with cgroup id
/sys/class/fc/fc_udev_device/*
With this new interface the user can set the application identfier
in  the blkcg associted with cgroup id.

This capability can be utilized by multiple block transport infrastructure
like fc,iscsi,roce.

Existing FC fabric will use this feature and the description of
the use case is below.

Various virtualization technologies used in Fibre Channel
SAN deployments have created the opportunity to identify
and associate traffic with specific virtualized applications.
The concepts behind the T11 Application Services standard is
to provide the general mechanisms needed to identify
virtualized services.
It enables the Fabric and the storage targets to
identify, monitor, and handle FC traffic
based on vm tags by inserting application specific identification
into the FC frame.

The patches were cut against  5.11/scsi-queue tree

v7:
Modified the Kconfig comments

v6:
Addressed the issues reported by kernel test robot
Modified the Kconfig files as per standard

v5:
Renamed the function cgroup_get_from_kernfs_id to
cgroup_get_from_id.

Moved the input validation at the beginning of the function in 
Renamed the arguments appropriatley.

Changed Return code to non-numeric/SymbolChanged Return code
to non-numeric/Symbol

Modified the comments.

v4:
Addressed the error reported by  kernel test robot

v3:
removed RFC.

Renamed the functions and app_id to more specific
Addressed the reference leaks in blkcg_set_app_identifier
Added a new config BLK_CGROUP_FC_APPID and made changes to 
select the same under SCSI_FC_ATTRS

V2:
renamed app_identifier to app_id.
removed the  sysfs interface blkio.app_identifie under
/sys/fs/cgroup/blkio
Ported the patch on top of 5.10/scsi-queue.
Removed redundant code due to changes since last submit.
Added a fix for issuing QFPA command.



Gaurav Srivastava (12):
  lpfc: vmid: Add the datastructure for supporting VMID in lpfc
  lpfc: vmid: Supplementary data structures for vmid and APIs
  lpfc: vmid: Forward declarations for APIs
  lpfc: vmid: VMID params initialization
  lpfc: vmid: Add support for vmid in mailbox command, does vmid
    resource allocation and vmid cleanup
  lpfc: vmid: Implements ELS commands for appid patch
  lpfc: vmid: Functions to manage vmids
  lpfc: vmid: Implements CT commands for appid.
  lpfc: vmid: Appends the vmid in the wqe before sending
  lpfc: vmid: Timeout implementation for vmid
  lpfc: vmid: Adding qfpa and vmid timeout check in worker thread
  lpfc: vmid: Introducing vmid in io path.

Muneendra (4):
  cgroup: Added cgroup_get_from_id
  blkcg: Added a app identifier support for blkcg
  nvme: Added a newsysfs attribute appid_store
  scsi: Made changes in Kconfig to select BLK_CGROUP_FC_APPID

 block/Kconfig                    |   9 +
 drivers/nvme/host/fc.c           |  73 +++++-
 drivers/scsi/Kconfig             |  13 ++
 drivers/scsi/lpfc/lpfc.h         | 121 ++++++++++
 drivers/scsi/lpfc/lpfc_attr.c    |  47 ++++
 drivers/scsi/lpfc/lpfc_crtn.h    |  11 +
 drivers/scsi/lpfc/lpfc_ct.c      | 252 +++++++++++++++++++++
 drivers/scsi/lpfc/lpfc_disc.h    |   1 +
 drivers/scsi/lpfc/lpfc_els.c     | 369 ++++++++++++++++++++++++++++++-
 drivers/scsi/lpfc/lpfc_hbadisc.c | 153 +++++++++++++
 drivers/scsi/lpfc/lpfc_hw.h      | 124 ++++++++++-
 drivers/scsi/lpfc/lpfc_hw4.h     |  12 +
 drivers/scsi/lpfc/lpfc_init.c    | 109 +++++++++
 drivers/scsi/lpfc/lpfc_mbox.c    |   6 +
 drivers/scsi/lpfc/lpfc_scsi.c    | 334 ++++++++++++++++++++++++++++
 drivers/scsi/lpfc/lpfc_sli.c     |  65 +++++-
 drivers/scsi/lpfc/lpfc_sli.h     |   8 +
 include/linux/blk-cgroup.h       |  56 +++++
 include/linux/cgroup.h           |   6 +
 kernel/cgroup/cgroup.c           |  26 +++
 20 files changed, 1782 insertions(+), 13 deletions(-)

-- 
2.26.2



From muneendra.kumar at broadcom.com  Wed Jan  6 17:00:16 2021
From: muneendra.kumar at broadcom.com (Muneendra)
Date: Thu,  7 Jan 2021 03:30:16 +0530
Subject: [PATCH v7 02/16] blkcg: Added a app identifier support for blkcg
In-Reply-To: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
References: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
Message-ID: <1609970430-19084-3-git-send-email-muneendra.kumar@broadcom.com>

This Patch added a unique application identifier i.e
fc_app_id  member in blkcg which allows identification of traffic
sources at an individual cgroup based Applications
(ex:virtual machine (VM))level in both host and
fabric infrastructure.

Added a new function blkcg_get_fc_appid to
grab the app identifier associated with a bio.

Added a new function blkcg_set_fc_appid to
set the app identifier in a blkcgrp associated with cgroup id

Added a new config BLK_CGROUP_FC_APPID and moved the changes
under this config

Signed-off-by: Muneendra <muneendra.kumar at broadcom.com>

---
v7:
Modified the Kconfig file

v6:
Modified the Kconfig file as per standard specified
in Documentation/process/coding-style.rst

v5:
Renamed the arguments appropriatley
Renamed APPID_LEN  to FC_APPID_LEN
Moved the input validation at the begining of the function
Modified the comments

v4:
No change

v3:
Renamed the functions and app_id to more specific

Addressed the reference leaks in blkcg_set_app_identifier

Added a new config BLK_CGROUP_FC_APPID and moved the changes
under this config

Added blkcg_get_fc_appid,blkcg_set_fc_appid as inline functions

v2:
renamed app_identifier to app_id
removed the  sysfs interface blkio.app_identifie under
---
 block/Kconfig              |  9 ++++++
 include/linux/blk-cgroup.h | 56 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 65 insertions(+)

diff --git a/block/Kconfig b/block/Kconfig
index a2297edfdde8..03886d105301 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -144,6 +144,15 @@ config BLK_CGROUP_IOLATENCY
 
 	Note, this is an experimental interface and could be changed someday.
 
+config BLK_CGROUP_FC_APPID
+	bool "Enable support to track FC I/O Traffic across cgroup applications"
+	depends on BLK_CGROUP=y
+	help
+	  Enabling this option enables the support to track FC I/O traffic across
+	  cgroup applications. It enables the Fabric and the storage targets to
+	  identify, monitor, and handle FC traffic based on VM tags by inserting
+	  application specific identification into the FC frame.
+
 config BLK_CGROUP_IOCOST
 	bool "Enable support for cost model based cgroup IO controller"
 	depends on BLK_CGROUP=y
diff --git a/include/linux/blk-cgroup.h b/include/linux/blk-cgroup.h
index c8fc9792ac77..216ca0d5eda7 100644
--- a/include/linux/blk-cgroup.h
+++ b/include/linux/blk-cgroup.h
@@ -30,6 +30,8 @@
 
 /* Max limits for throttle policy */
 #define THROTL_IOPS_MAX		UINT_MAX
+#define FC_APPID_LEN              129
+
 
 #ifdef CONFIG_BLK_CGROUP
 
@@ -55,6 +57,9 @@ struct blkcg {
 	struct blkcg_policy_data	*cpd[BLKCG_MAX_POLS];
 
 	struct list_head		all_blkcgs_node;
+#ifdef CONFIG_BLK_CGROUP_FC_APPID
+	char                            fc_app_id[FC_APPID_LEN];
+#endif
 #ifdef CONFIG_CGROUP_WRITEBACK
 	struct list_head		cgwb_list;
 #endif
@@ -660,4 +665,55 @@ static inline void blk_cgroup_bio_start(struct bio *bio) { }
 
 #endif	/* CONFIG_BLOCK */
 #endif	/* CONFIG_BLK_CGROUP */
+
+#ifdef CONFIG_BLK_CGROUP_FC_APPID
+/*
+ * Sets the fc_app_id field associted to blkcg
+ * @app_id: application identifier
+ * @cgrp_id: cgroup id
+ * @app_id_len: size of application identifier
+ */
+static inline int blkcg_set_fc_appid(char *app_id, u64 cgrp_id, size_t app_id_len)
+{
+	struct cgroup *cgrp;
+	struct cgroup_subsys_state *css;
+	struct blkcg *blkcg;
+	int ret  = 0;
+
+	if (app_id_len > FC_APPID_LEN)
+		return -EINVAL;
+
+	cgrp = cgroup_get_from_id(cgrp_id);
+	if (!cgrp)
+		return -ENOENT;
+	css = cgroup_get_e_css(cgrp, &io_cgrp_subsys);
+	if (!css) {
+		ret = -ENOENT;
+		goto out_cgrp_put;
+	}
+	blkcg = css_to_blkcg(css);
+	strlcpy(blkcg->fc_app_id, app_id, app_id_len);
+	css_put(css);
+out_cgrp_put:
+	cgroup_put(cgrp);
+	return ret;
+}
+
+/**
+ * blkcg_get_fc_appid - get the fc app identifier associated with a bio
+ * @bio: target bio
+ *
+ * On success it returns the fc_app_id on failure it returns NULL
+ */
+static inline char *blkcg_get_fc_appid(struct bio *bio)
+{
+	if (bio && bio->bi_blkg &&
+		(bio->bi_blkg->blkcg->fc_app_id[0] != '\0'))
+		return bio->bi_blkg->blkcg->fc_app_id;
+	return NULL;
+}
+#else
+static inline int blkcg_set_fc_appid(char *buf, u64 id, size_t len) { return -EINVAL; }
+static inline char *blkcg_get_fc_appid(struct bio *bio) { return NULL; }
+#endif /*CONFIG_BLK_CGROUP_FC_APPID*/
 #endif	/* _BLK_CGROUP_H */
-- 
2.26.2



From muneendra.kumar at broadcom.com  Wed Jan  6 17:00:20 2021
From: muneendra.kumar at broadcom.com (Muneendra)
Date: Thu,  7 Jan 2021 03:30:20 +0530
Subject: [PATCH v7 06/16] lpfc: vmid: Forward declarations for APIs
In-Reply-To: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
References: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
Message-ID: <1609970430-19084-7-git-send-email-muneendra.kumar@broadcom.com>

From: Gaurav Srivastava <gaurav.srivastava at broadcom.com>

This patch contains the forward declarations of commonly used APIs which
are used outside the scope of the file.

Signed-off-by: Gaurav Srivastava <gaurav.srivastava at broadcom.com>
Signed-off-by: James Smart <jsmart2021 at gmail.com>

---
v7:
No change

v6:
No change

v5:
No change

v4:
No change

v3:
No change

v2:
Ported the patch on top of 5.10/scsi-queue
---
 drivers/scsi/lpfc/lpfc_crtn.h | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index f78e52a18b0b..7eb0200ecaa8 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -606,3 +606,14 @@ extern unsigned long lpfc_no_hba_reset[];
 extern union lpfc_wqe128 lpfc_iread_cmd_template;
 extern union lpfc_wqe128 lpfc_iwrite_cmd_template;
 extern union lpfc_wqe128 lpfc_icmnd_cmd_template;
+
+/* vmid interface */
+int lpfc_vmid_uvem(struct lpfc_vport *vport, struct lpfc_vmid *vmid, bool ins);
+uint32_t lpfc_vmid_get_cs_ctl(struct lpfc_vport *vport);
+int lpfc_vmid_cmd(struct lpfc_vport *vport,
+		  int cmdcode, struct lpfc_vmid *vmid);
+int lpfc_vmid_hash_fn(char *vmid, int len);
+struct lpfc_vmid *lpfc_get_vmid_from_hastable(struct lpfc_vport *vport,
+					      uint32_t hash, uint8_t *buf);
+void lpfc_vmid_vport_cleanup(struct lpfc_vport *vport);
+int lpfc_issue_els_qfpa(struct lpfc_vport *vport);
-- 
2.26.2



From muneendra.kumar at broadcom.com  Wed Jan  6 17:00:19 2021
From: muneendra.kumar at broadcom.com (Muneendra)
Date: Thu,  7 Jan 2021 03:30:19 +0530
Subject: [PATCH v7 05/16] lpfc: vmid: Supplementary data structures for vmid
 and APIs
In-Reply-To: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
References: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
Message-ID: <1609970430-19084-6-git-send-email-muneendra.kumar@broadcom.com>

From: Gaurav Srivastava <gaurav.srivastava at broadcom.com>

This patch adds additional data structures for supporting the two
versions of vmid implementation. First type uses app header while
the other types uses priority tagging mechanism. These data
structures are used mostly for ELS and CT commands for the
two vmid implementation.

The API determines if VMID is enabled by the user or not.

Signed-off-by: Gaurav Srivastava <gaurav.srivastava at broadcom.com>
Signed-off-by: James Smart <jsmart2021 at gmail.com>

---
v7:
No change

v6:
No change

v5:
Merged the patch5 of v4 to this patch
Uniform data type naming scheme

v4:
No change

v3:
No change

v2:
Ported the patch on top of 5.10/scsi-queue
---
 drivers/scsi/lpfc/lpfc.h      |  24 +++++++
 drivers/scsi/lpfc/lpfc_disc.h |   1 +
 drivers/scsi/lpfc/lpfc_hw.h   | 124 ++++++++++++++++++++++++++++++++--
 drivers/scsi/lpfc/lpfc_sli.h  |   8 +++
 4 files changed, 153 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index ab61352363d4..6d9617c47db0 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -1513,3 +1513,27 @@ static const char *routine(enum enum_name table_key)			\
 	}								\
 	return name;							\
 }
+
+/**
+ * lpfc_is_vmid_enabled - returns if VMID is enabled for either switch types
+ * @phba: Pointer to HBA context object.
+ *
+ * Relationship between the enable, target support and if vmid tag is required
+ * for the particular combination
+ * ---------------------------------------------------
+ * Switch    Enable Flag  Target Support  VMID Needed
+ * ---------------------------------------------------
+ * App Id     0              NA              N
+ * App Id     1               0              N
+ * App Id     1               1              Y
+ * Pr Tag     0              NA              N
+ * Pr Tag     1               0              N
+ * Pr Tag     1               1              Y
+ * Pr Tag     2               *              Y
+ ---------------------------------------------------
+ *
+ **/
+static inline int lpfc_is_vmid_enabled(struct lpfc_hba *phba)
+{
+	return phba->cfg_vmid_app_header || phba->cfg_vmid_priority_tagging;
+}
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
index ea07afcb750a..25d119c005dd 100644
--- a/drivers/scsi/lpfc/lpfc_disc.h
+++ b/drivers/scsi/lpfc/lpfc_disc.h
@@ -117,6 +117,7 @@ struct lpfc_nodelist {
 	uint8_t         nlp_fcp_info;	        /* class info, bits 0-3 */
 #define NLP_FCP_2_DEVICE   0x10			/* FCP-2 device */
 	u8		nlp_nvme_info;	        /* NVME NSLER Support */
+	uint8_t		vmid_support;		/* destination VMID support */
 #define NLP_NVME_NSLER     0x1			/* NVME NSLER device */
 
 	struct timer_list   nlp_delayfunc;	/* Used for delayed ELS cmds */
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index 42682d95af52..4a5a85ed42ec 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -275,6 +275,7 @@ struct lpfc_sli_ct_request {
 #define  SLI_CT_ACCESS_DENIED             0x10
 #define  SLI_CT_INVALID_PORT_ID           0x11
 #define  SLI_CT_DATABASE_EMPTY            0x12
+#define  SLI_CT_APP_ID_NOT_AVAILABLE      0x40
 
 /*
  * Name Server Command Codes
@@ -400,16 +401,16 @@ struct csp {
 	uint16_t altBbCredit:1;	/* FC Word 1, bit 27 */
 	uint16_t edtovResolution:1;	/* FC Word 1, bit 26 */
 	uint16_t multicast:1;	/* FC Word 1, bit 25 */
-	uint16_t broadcast:1;	/* FC Word 1, bit 24 */
+	uint16_t app_hdr_support:1;	/* FC Word 1, bit 24 */
 
-	uint16_t huntgroup:1;	/* FC Word 1, bit 23 */
+	uint16_t priority_tagging:1;	/* FC Word 1, bit 23 */
 	uint16_t simplex:1;	/* FC Word 1, bit 22 */
 	uint16_t word1Reserved1:3;	/* FC Word 1, bit 21:19 */
 	uint16_t dhd:1;		/* FC Word 1, bit 18 */
 	uint16_t contIncSeqCnt:1;	/* FC Word 1, bit 17 */
 	uint16_t payloadlength:1;	/* FC Word 1, bit 16 */
 #else	/*  __LITTLE_ENDIAN_BITFIELD */
-	uint16_t broadcast:1;	/* FC Word 1, bit 24 */
+	uint16_t app_hdr_support:1;	/* FC Word 1, bit 24 */
 	uint16_t multicast:1;	/* FC Word 1, bit 25 */
 	uint16_t edtovResolution:1;	/* FC Word 1, bit 26 */
 	uint16_t altBbCredit:1;	/* FC Word 1, bit 27 */
@@ -423,7 +424,7 @@ struct csp {
 	uint16_t dhd:1;		/* FC Word 1, bit 18 */
 	uint16_t word1Reserved1:3;	/* FC Word 1, bit 21:19 */
 	uint16_t simplex:1;	/* FC Word 1, bit 22 */
-	uint16_t huntgroup:1;	/* FC Word 1, bit 23 */
+	uint16_t priority_tagging:1;	/* FC Word 1, bit 23 */
 #endif
 
 	uint8_t bbRcvSizeMsb;	/* Upper nibble is reserved */
@@ -607,6 +608,8 @@ struct fc_vft_header {
 #define ELS_CMD_LIRR      0x7A000000
 #define ELS_CMD_LCB	  0x81000000
 #define ELS_CMD_FPIN	  0x16000000
+#define ELS_CMD_QFPA      0xB0000000
+#define ELS_CMD_UVEM      0xB1000000
 #else	/*  __LITTLE_ENDIAN_BITFIELD */
 #define ELS_CMD_MASK      0xffff
 #define ELS_RSP_MASK      0xff
@@ -649,6 +652,8 @@ struct fc_vft_header {
 #define ELS_CMD_LIRR      0x7A
 #define ELS_CMD_LCB	  0x81
 #define ELS_CMD_FPIN	  ELS_FPIN
+#define ELS_CMD_QFPA      0xB0
+#define ELS_CMD_UVEM      0xB1
 #endif
 
 /*
@@ -1317,6 +1322,117 @@ struct fc_rdp_res_frame {
 };
 
 
+/* UVEM */
+
+#define LPFC_UVEM_SIZE 60
+#define LPFC_UVEM_VEM_ID_DESC_SIZE 16
+#define LPFC_UVEM_VE_MAP_DESC_SIZE 20
+
+#define VEM_ID_DESC_TAG  0x0001000A
+struct lpfc_vem_id_desc {
+	uint32_t tag;
+	uint32_t length;
+	uint8_t vem_id[16];
+};
+
+#define LPFC_QFPA_SIZE	4
+
+#define INSTANTIATED_VE_DESC_TAG  0x0001000B
+struct instantiated_ve_desc {
+	uint32_t tag;
+	uint32_t length;
+	uint8_t global_vem_id[16];
+	uint32_t word6;
+#define lpfc_instantiated_local_id_SHIFT   0
+#define lpfc_instantiated_local_id_MASK    0x000000ff
+#define lpfc_instantiated_local_id_WORD    word6
+#define lpfc_instantiated_nport_id_SHIFT   8
+#define lpfc_instantiated_nport_id_MASK    0x00ffffff
+#define lpfc_instantiated_nport_id_WORD    word6
+};
+
+#define DEINSTANTIATED_VE_DESC_TAG  0x0001000C
+struct deinstantiated_ve_desc {
+	uint32_t tag;
+	uint32_t length;
+	uint8_t global_vem_id[16];
+	uint32_t word6;
+#define lpfc_deinstantiated_nport_id_SHIFT   0
+#define lpfc_deinstantiated_nport_id_MASK    0x000000ff
+#define lpfc_deinstantiated_nport_id_WORD    word6
+#define lpfc_deinstantiated_local_id_SHIFT   24
+#define lpfc_deinstantiated_local_id_MASK    0x00ffffff
+#define lpfc_deinstantiated_local_id_WORD    word6
+};
+
+/* Query Fabric Priority Allocation Response */
+#define LPFC_PRIORITY_RANGE_DESC_SIZE 12
+
+struct priority_range_desc {
+	uint32_t tag;
+	uint32_t length;
+	uint8_t lo_range;
+	uint8_t hi_range;
+	uint8_t qos_priority;
+	uint8_t local_ve_id;
+};
+
+struct fc_qfpa_res {
+	uint32_t reply_sequence;	/* LS_ACC or LS_RJT */
+	uint32_t length;	/* FC Word 1    */
+	struct priority_range_desc desc[1];
+};
+
+/* Application Server command code */
+/* VMID               */
+
+#define SLI_CT_APP_SEV_Subtypes     0x20	/* Application Server subtype */
+
+#define SLI_CTAS_GAPPIA_ENT    0x0100	/* Get Application Identifier */
+#define SLI_CTAS_GALLAPPIA     0x0101	/* Get All Application Identifier */
+#define SLI_CTAS_GALLAPPIA_ID  0x0102	/* Get All Application Identifier */
+					/* for Nport */
+#define SLI_CTAS_GAPPIA_IDAPP  0x0103	/* Get Application Identifier */
+					/* for Nport */
+#define SLI_CTAS_RAPP_IDENT    0x0200	/* Register Application Identifier */
+#define SLI_CTAS_DAPP_IDENT    0x0300	/* Deregister Application */
+					/* Identifier */
+#define SLI_CTAS_DALLAPP_ID    0x0301	/* Deregister All Application */
+					/* Identifier */
+
+struct entity_id_object {
+	uint8_t entity_id_len;
+	uint8_t entity_id[255];	/* VM UUID */
+};
+
+struct app_id_object {
+	uint32_t port_id;
+	uint32_t app_id;
+	struct entity_id_object obj;
+};
+
+struct lpfc_vmid_rapp_ident_list {
+	uint32_t no_of_objects;
+	struct entity_id_object obj[1];
+};
+
+struct lpfc_vmid_dapp_ident_list {
+	uint32_t no_of_objects;
+	struct entity_id_object obj[1];
+};
+
+#define GALLAPPIA_ID_LAST  0x80
+struct lpfc_vmid_gallapp_ident_list {
+	uint8_t control;
+	uint8_t reserved[3];
+	struct app_id_object app_id;
+};
+
+#define RAPP_IDENT_OFFSET  (offsetof(struct lpfc_sli_ct_request, un) + 4)
+#define DAPP_IDENT_OFFSET  (offsetof(struct lpfc_sli_ct_request, un) + 4)
+#define GALLAPPIA_ID_SIZE  (offsetof(struct lpfc_sli_ct_request, un) + 4)
+#define DALLAPP_ID_SIZE    (offsetof(struct lpfc_sli_ct_request, un) + 4)
+
 /******** FDMI ********/
 
 /* lpfc_sli_ct_request defines the CT_IU preamble for FDMI commands */
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index 4f6936014ff5..ff5a2a492405 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -35,6 +35,12 @@ typedef enum _lpfc_ctx_cmd {
 	LPFC_CTX_HOST
 } lpfc_ctx_cmd;
 
+union lpfc_vmid_iocb_tag {
+	uint32_t app_id;
+	uint8_t cs_ctl_vmid;
+	struct lpfc_vmid_context *vmid_context;	/* UVEM context information */
+};
+
 struct lpfc_cq_event {
 	struct list_head list;
 	uint16_t hdwq;
@@ -100,6 +106,7 @@ struct lpfc_iocbq {
 #define LPFC_IO_NVME	        0x200000 /* NVME FCP command */
 #define LPFC_IO_NVME_LS		0x400000 /* NVME LS command */
 #define LPFC_IO_NVMET		0x800000 /* NVMET command */
+#define LPFC_IO_VMID            0x1000000 /* VMID tagged IO */
 
 	uint32_t drvrTimeout;	/* driver timeout in seconds */
 	struct lpfc_vport *vport;/* virtual port pointer */
@@ -114,6 +121,7 @@ struct lpfc_iocbq {
 		struct lpfc_node_rrq *rrq;
 	} context_un;
 
+	union lpfc_vmid_iocb_tag vmid_tag;
 	void (*fabric_iocb_cmpl)(struct lpfc_hba *, struct lpfc_iocbq *,
 			   struct lpfc_iocbq *);
 	void (*wait_iocb_cmpl)(struct lpfc_hba *, struct lpfc_iocbq *,
-- 
2.26.2



From muneendra.kumar at broadcom.com  Wed Jan  6 17:00:21 2021
From: muneendra.kumar at broadcom.com (Muneendra)
Date: Thu,  7 Jan 2021 03:30:21 +0530
Subject: [PATCH v7 07/16] lpfc: vmid: VMID params initialization
In-Reply-To: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
References: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
Message-ID: <1609970430-19084-8-git-send-email-muneendra.kumar@broadcom.com>

From: Gaurav Srivastava <gaurav.srivastava at broadcom.com>

This patch initializes the VMID parameters like the type of vmid, max
number of vmids supported and timeout value for the vmid registration
based on the user input.

Signed-off-by: Gaurav Srivastava <gaurav.srivastava at broadcom.com>
Signed-off-by: James Smart <jsmart2021 at gmail.com>

---
v7:
No change

v6:
No change

v5:
No change

v4:
No change

v3:
No change

v2:
Ported the patch on top of 5.10/scsi-queue
---
 drivers/scsi/lpfc/lpfc_attr.c | 47 +++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 4528166dee36..d8cca950fa3b 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -6151,6 +6151,44 @@ LPFC_ATTR_RW(enable_dpp, 1, 0, 1, "Enable Direct Packet Push");
  */
 LPFC_ATTR_R(enable_mi, 1, 0, 1, "Enable MI");
 
+/*
+ * lpfc_max_vmid: Maximum number of VMs to be tagged. This is valid only if
+ * either vmid_app_header or vmid_priority_tagging is enabled.
+ *       4 - 255  = vmid support enabled for 4-255 VMs
+ *       Value range is [4,255].
+ */
+LPFC_ATTR_RW(max_vmid, LPFC_MIN_VMID, LPFC_MIN_VMID, LPFC_MAX_VMID,
+	     "Maximum number of VMs supported");
+
+/*
+ * lpfc_vmid_inactivity_timeout: Inactivity timeout duration in hours
+ *       0  = Timeout is disabled
+ * Value range is [0,24].
+ */
+LPFC_ATTR_RW(vmid_inactivity_timeout, 4, 0, 24,
+	     "Inactivity timeout in hours");
+
+/*
+ * lpfc_vmid_app_header: Enable App Header VMID support
+ *       0  = Support is disabled (default)
+ *       1  = Support is enabled
+ * Value range is [0,1].
+ */
+LPFC_ATTR_RW(vmid_app_header, LPFC_VMID_APP_HEADER_DISABLE,
+	     LPFC_VMID_APP_HEADER_DISABLE, LPFC_VMID_APP_HEADER_ENABLE,
+	     "Enable App Header VMID support");
+
+/*
+ * lpfc_vmid_priority_tagging: Enable Priority Tagging VMID support
+ *       0  = Support is disabled (default)
+ *       1  = Support is enabled
+ * Value range is [0,1]..
+ */
+LPFC_ATTR_RW(vmid_priority_tagging, LPFC_VMID_PRIO_TAG_DISABLE,
+	     LPFC_VMID_PRIO_TAG_DISABLE,
+	     LPFC_VMID_PRIO_TAG_ALL_TARGETS,
+	     "Enable Priority Tagging VMID support");
+
 struct device_attribute *lpfc_hba_attrs[] = {
 	&dev_attr_nvme_info,
 	&dev_attr_scsi_stat,
@@ -6269,6 +6307,10 @@ struct device_attribute *lpfc_hba_attrs[] = {
 	&dev_attr_lpfc_enable_bbcr,
 	&dev_attr_lpfc_enable_dpp,
 	&dev_attr_lpfc_enable_mi,
+	&dev_attr_lpfc_max_vmid,
+	&dev_attr_lpfc_vmid_inactivity_timeout,
+	&dev_attr_lpfc_vmid_app_header,
+	&dev_attr_lpfc_vmid_priority_tagging,
 	NULL,
 };
 
@@ -7328,6 +7370,11 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
 	lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat);
 
 	lpfc_EnableXLane_init(phba, lpfc_EnableXLane);
+	/* VMID Inits */
+	lpfc_max_vmid_init(phba, lpfc_max_vmid);
+	lpfc_vmid_inactivity_timeout_init(phba, lpfc_vmid_inactivity_timeout);
+	lpfc_vmid_app_header_init(phba, lpfc_vmid_app_header);
+	lpfc_vmid_priority_tagging_init(phba, lpfc_vmid_priority_tagging);
 	if (phba->sli_rev != LPFC_SLI_REV4)
 		phba->cfg_EnableXLane = 0;
 	lpfc_XLanePriority_init(phba, lpfc_XLanePriority);
-- 
2.26.2



From muneendra.kumar at broadcom.com  Wed Jan  6 17:00:22 2021
From: muneendra.kumar at broadcom.com (Muneendra)
Date: Thu,  7 Jan 2021 03:30:22 +0530
Subject: [PATCH v7 08/16] lpfc: vmid: Add support for vmid in mailbox command,
 does vmid resource allocation and vmid cleanup
In-Reply-To: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
References: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
Message-ID: <1609970430-19084-9-git-send-email-muneendra.kumar@broadcom.com>

From: Gaurav Srivastava <gaurav.srivastava at broadcom.com>

This patch does the following -
1.adds supporting datastructures for mailbox command which helps in
determining if the firmware supports appid or not.
2.This patch allocates the resource for vmid and checks if the firmware
supports the feature or not.
3.The patch cleans up the vmid resources and stops the timer.

Reported-by: kernel test robot <lkp at intel.com>
Signed-off-by: Gaurav Srivastava <gaurav.srivastava at broadcom.com>
Signed-off-by: James Smart <jsmart2021 at gmail.com>

---
v7:
No change

v6:
Added Forward declarations and functions to static

v5:
Merged patches 8 and 11 of v4 to this patch
Changed Return code to non-numeric/Symbol

v4:
No change

v3:
No change

v2:
Ported the patch on top of 5.10/scsi-queue
---
 drivers/scsi/lpfc/lpfc_hw4.h  | 12 ++++++
 drivers/scsi/lpfc/lpfc_init.c | 69 +++++++++++++++++++++++++++++++++++
 drivers/scsi/lpfc/lpfc_mbox.c |  6 +++
 drivers/scsi/lpfc/lpfc_scsi.c | 21 +++++++++++
 drivers/scsi/lpfc/lpfc_sli.c  |  9 +++++
 5 files changed, 117 insertions(+)

diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index 541b9aef6bfe..5fdafc92fc2d 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -272,6 +272,9 @@ struct lpfc_sli4_flags {
 #define lpfc_vfi_rsrc_rdy_MASK		0x00000001
 #define lpfc_vfi_rsrc_rdy_WORD		word0
 #define LPFC_VFI_RSRC_RDY		1
+#define lpfc_ftr_ashdr_SHIFT            4
+#define lpfc_ftr_ashdr_MASK             0x00000001
+#define lpfc_ftr_ashdr_WORD             word0
 };
 
 struct sli4_bls_rsp {
@@ -2943,6 +2946,9 @@ struct lpfc_mbx_request_features {
 #define lpfc_mbx_rq_ftr_rq_mrqp_SHIFT		16
 #define lpfc_mbx_rq_ftr_rq_mrqp_MASK		0x00000001
 #define lpfc_mbx_rq_ftr_rq_mrqp_WORD		word2
+#define lpfc_mbx_rq_ftr_rq_ashdr_SHIFT          17
+#define lpfc_mbx_rq_ftr_rq_ashdr_MASK           0x00000001
+#define lpfc_mbx_rq_ftr_rq_ashdr_WORD           word2
 	uint32_t word3;
 #define lpfc_mbx_rq_ftr_rsp_iaab_SHIFT		0
 #define lpfc_mbx_rq_ftr_rsp_iaab_MASK		0x00000001
@@ -2974,6 +2980,9 @@ struct lpfc_mbx_request_features {
 #define lpfc_mbx_rq_ftr_rsp_mrqp_SHIFT		16
 #define lpfc_mbx_rq_ftr_rsp_mrqp_MASK		0x00000001
 #define lpfc_mbx_rq_ftr_rsp_mrqp_WORD		word3
+#define lpfc_mbx_rq_ftr_rsp_ashdr_SHIFT         17
+#define lpfc_mbx_rq_ftr_rsp_ashdr_MASK          0x00000001
+#define lpfc_mbx_rq_ftr_rsp_ashdr_WORD          word3
 };
 
 struct lpfc_mbx_supp_pages {
@@ -4391,6 +4400,9 @@ struct wqe_common {
 #define wqe_xchg_WORD         word10
 #define LPFC_SCSI_XCHG	      0x0
 #define LPFC_NVME_XCHG	      0x1
+#define wqe_appid_SHIFT       5
+#define wqe_appid_MASK        0x00000001
+#define wqe_appid_WORD        word10
 #define wqe_oas_SHIFT         6
 #define wqe_oas_MASK          0x00000001
 #define wqe_oas_WORD          word10
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index ac67f420ec26..dea423bc1293 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -98,6 +98,7 @@ static struct scsi_transport_template *lpfc_transport_template = NULL;
 static struct scsi_transport_template *lpfc_vport_transport_template = NULL;
 static DEFINE_IDR(lpfc_hba_index);
 #define LPFC_NVMET_BUF_POST 254
+static u8 lpfc_vmid_res_alloc(struct lpfc_hba *phba, struct lpfc_vport *vport);
 
 /**
  * lpfc_config_port_prep - Perform lpfc initialization prior to config port
@@ -2843,6 +2844,10 @@ lpfc_cleanup(struct lpfc_vport *vport)
 	if (phba->link_state > LPFC_LINK_DOWN)
 		lpfc_port_link_failure(vport);
 
+	/* cleanup vmid resources */
+	if (lpfc_is_vmid_enabled(phba))
+		lpfc_vmid_vport_cleanup(vport);
+
 	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
 		if (vport->port_type != LPFC_PHYSICAL_PORT &&
 		    ndlp->nlp_DID == Fabric_DID) {
@@ -4269,6 +4274,62 @@ lpfc_get_wwpn(struct lpfc_hba *phba)
 		return rol64(wwn, 32);
 }
 
+/**
+ * lpfc_vmid_res_alloc - Allocates resources for VMID
+ * @phba: pointer to lpfc hba data structure.
+ * @vport: pointer to vport data structure
+ *
+ * This routine allocated the resources needed for the vmid.
+ *
+ * Return codes
+ *	0 on Succeess
+ *	Non-0 on Failure
+ */
+static u8
+lpfc_vmid_res_alloc(struct lpfc_hba *phba, struct lpfc_vport *vport)
+{
+	u16 i;
+
+	/* vmid feature is supported only on SLI4 */
+	if (phba->sli_rev == LPFC_SLI_REV3) {
+		phba->cfg_vmid_app_header = 0;
+		phba->cfg_vmid_priority_tagging = 0;
+	}
+
+	/* if enabled, then allocated the resources */
+	if (lpfc_is_vmid_enabled(phba)) {
+		vport->vmid =
+		    kmalloc_array(phba->cfg_max_vmid, sizeof(struct lpfc_vmid),
+				  GFP_KERNEL);
+		if (!vport->vmid)
+			return FAILURE;
+
+		memset(vport->vmid, 0,
+		       phba->cfg_max_vmid * sizeof(struct lpfc_vmid));
+
+		rwlock_init(&vport->vmid_lock);
+
+		/* setting the VMID parameters for the vport */
+		vport->vmid_priority_tagging = phba->cfg_vmid_priority_tagging;
+		vport->vmid_inactivity_timeout =
+		    phba->cfg_vmid_inactivity_timeout;
+		vport->max_vmid = phba->cfg_max_vmid;
+		vport->cur_vmid_cnt = 0;
+
+		for (i = 0; i < LPFC_VMID_HASH_SIZE; i++)
+			vport->hash_table[i] = NULL;
+
+		vport->vmid_priority_range = bitmap_zalloc
+			(LPFC_VMID_MAX_PRIORITY_RANGE, GFP_KERNEL);
+
+		if (!vport->vmid_priority_range) {
+			kfree(vport->vmid);
+			return FAILURE;
+		}
+	}
+	return 0;
+}
+
 /**
  * lpfc_create_port - Create an FC port
  * @phba: pointer to lpfc hba data structure.
@@ -4421,6 +4482,12 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
 			vport->port_type, shost->sg_tablesize,
 			phba->cfg_scsi_seg_cnt, phba->cfg_sg_seg_cnt);
 
+	/* allocate the resources for vmid */
+	rc = lpfc_vmid_res_alloc(phba, vport);
+
+	if (rc)
+		goto out;
+
 	/* Initialize all internally managed lists. */
 	INIT_LIST_HEAD(&vport->fc_nodes);
 	INIT_LIST_HEAD(&vport->rcv_buffer_list);
@@ -4445,6 +4512,8 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
 	return vport;
 
 out_put_shost:
+	kfree(vport->vmid);
+	bitmap_free(vport->vmid_priority_range);
 	scsi_host_put(shost);
 out:
 	return NULL;
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index 3414ffcb26fe..78a9b9baecf3 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -2100,6 +2100,12 @@ lpfc_request_features(struct lpfc_hba *phba, struct lpfcMboxq *mboxq)
 		bf_set(lpfc_mbx_rq_ftr_rq_iaab, &mboxq->u.mqe.un.req_ftrs, 0);
 		bf_set(lpfc_mbx_rq_ftr_rq_iaar, &mboxq->u.mqe.un.req_ftrs, 0);
 	}
+
+	/* Enable Application Services Header for apphedr VMID */
+	if (phba->cfg_vmid_app_header) {
+		bf_set(lpfc_mbx_rq_ftr_rq_ashdr, &mboxq->u.mqe.un.req_ftrs, 1);
+		bf_set(lpfc_ftr_ashdr, &phba->sli4_hba.sli4_flags, 1);
+	}
 	return;
 }
 
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 3b989f720937..b79b6f03cdb6 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -5370,6 +5370,27 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd)
 	return 0;
 }
 
+/*
+ * lpfc_vmid_vport_cleanup - cleans up the resources associated with a vports
+ * @vport: The virtual port for which this call is being executed.
+ */
+void lpfc_vmid_vport_cleanup(struct lpfc_vport *vport)
+{
+	/* delete the timer */
+	if (vport->port_type == LPFC_PHYSICAL_PORT)
+		del_timer_sync(&vport->phba->inactive_vmid_poll);
+
+	/* free the resources */
+	kfree(vport->qfpa_res);
+	kfree(vport->vmid_priority.vmid_range);
+	kfree(vport->vmid);
+
+	/* reset variables */
+	vport->qfpa_res = NULL;
+	vport->vmid_priority.vmid_range = NULL;
+	vport->vmid = NULL;
+	vport->cur_vmid_cnt = 0;
+}
 
 /**
  * lpfc_abort_handler - scsi_host_template eh_abort_handler entry point
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 95caad764fb7..f9b6e32db618 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -7696,6 +7696,15 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
 		goto out_free_mbox;
 	}
 
+	/* Disable vmid if app header is not supported */
+	if (phba->cfg_vmid_app_header && !(bf_get(lpfc_mbx_rq_ftr_rsp_ashdr,
+						  &mqe->un.req_ftrs))) {
+		bf_set(lpfc_ftr_ashdr, &phba->sli4_hba.sli4_flags, 0);
+		phba->cfg_vmid_app_header = 0;
+		lpfc_printf_log(phba, KERN_DEBUG, LOG_SLI,
+				"1242 vmid feature not supported");
+	}
+
 	/*
 	 * The port must support FCP initiator mode as this is the
 	 * only mode running in the host.
-- 
2.26.2



From muneendra.kumar at broadcom.com  Wed Jan  6 17:00:26 2021
From: muneendra.kumar at broadcom.com (Muneendra)
Date: Thu,  7 Jan 2021 03:30:26 +0530
Subject: [PATCH v7 12/16] lpfc: vmid: Appends the vmid in the wqe before
 sending
In-Reply-To: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
References: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
Message-ID: <1609970430-19084-13-git-send-email-muneendra.kumar@broadcom.com>

From: Gaurav Srivastava <gaurav.srivastava at broadcom.com>

This patch adds the vmid in wqe before sending out the request.
The type of vmid depends on the configured type and is checked before
being appended.

Signed-off-by: Gaurav Srivastava  <gaurav.srivastava at broadcom.com>
Signed-off-by: James Smart <jsmart2021 at gmail.com>

---
v7:
No change

v6:
No change

v5:
Modified the comments

v4:
No change

v3:
No change

v2:
Ported the patch on top of 5.10/scsi-queue
---
 drivers/scsi/lpfc/lpfc_sli.c | 56 +++++++++++++++++++++++++++++++++++-
 1 file changed, 55 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index f9b6e32db618..a63371e9feaa 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -3856,7 +3856,7 @@ lpfc_sli_sp_handle_rspiocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 
 		if (irsp->ulpStatus) {
 			/* Rsp ring <ringno> error: IOCB */
-			lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+			lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
 					"0328 Rsp Ring %d error: "
 					"IOCB Data: "
 					"x%x x%x x%x x%x "
@@ -9762,6 +9762,8 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
 				*pcmd == ELS_CMD_RSCN_XMT ||
 				*pcmd == ELS_CMD_FDISC ||
 				*pcmd == ELS_CMD_LOGO ||
+				*pcmd == ELS_CMD_QFPA ||
+				*pcmd == ELS_CMD_UVEM ||
 				*pcmd == ELS_CMD_PLOGI)) {
 				bf_set(els_req64_sp, &wqe->els_req, 1);
 				bf_set(els_req64_sid, &wqe->els_req,
@@ -9893,6 +9895,24 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
 			ptr = &wqe->words[22];
 			memcpy(ptr, fcp_cmnd, sizeof(struct fcp_cmnd));
 		}
+
+		/* add the VMID tags as per switch response */
+		if (iocbq->iocb_flag & LPFC_IO_VMID) {
+			union lpfc_wqe128 *wqe128;
+
+			if (phba->pport->vmid_priority_tagging) {
+				bf_set(wqe_ccpe, &wqe->fcp_iwrite.wqe_com, 1);
+				bf_set(wqe_ccp, &wqe->fcp_iwrite.wqe_com,
+				       (iocbq->vmid_tag.cs_ctl_vmid));
+				/* Bit 0 must be 0 */
+			} else {
+				wqe128 = (union lpfc_wqe128 *)wqe;
+				bf_set(wqe_appid, &wqe->fcp_iwrite.wqe_com, 1);
+				bf_set(wqe_wqes, &wqe128->fcp_iwrite.wqe_com,
+				       1);
+				wqe128->words[31] = iocbq->vmid_tag.app_id;
+			}
+		}
 		break;
 	case CMD_FCP_IREAD64_CR:
 		/* word3 iocb=iotag wqe=payload_offset_len */
@@ -9957,6 +9977,23 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
 			ptr = &wqe->words[22];
 			memcpy(ptr, fcp_cmnd, sizeof(struct fcp_cmnd));
 		}
+
+		/* add the VMID tags as per switch response */
+		if (iocbq->iocb_flag & LPFC_IO_VMID) {
+			union lpfc_wqe128 *wqe128;
+
+			if (phba->pport->vmid_priority_tagging) {
+				bf_set(wqe_ccpe, &wqe->fcp_iread.wqe_com, 1);
+				bf_set(wqe_ccp, &wqe->fcp_iread.wqe_com,
+				       (iocbq->vmid_tag.cs_ctl_vmid));
+				/* Bit 0 must be 0 */
+			} else {
+				wqe128 = (union lpfc_wqe128 *)wqe;
+				bf_set(wqe_appid, &wqe->fcp_iread.wqe_com, 1);
+				bf_set(wqe_wqes, &wqe128->fcp_iread.wqe_com, 1);
+				wqe128->words[31] = iocbq->vmid_tag.app_id;
+			}
+		}
 		break;
 	case CMD_FCP_ICMND64_CR:
 		/* word3 iocb=iotag wqe=payload_offset_len */
@@ -10014,6 +10051,23 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
 			ptr = &wqe->words[22];
 			memcpy(ptr, fcp_cmnd, sizeof(struct fcp_cmnd));
 		}
+
+		/* add the VMID tags as per switch response */
+		if (iocbq->iocb_flag & LPFC_IO_VMID) {
+			union lpfc_wqe128 *wqe128;
+
+			if (phba->pport->vmid_priority_tagging) {
+				bf_set(wqe_ccpe, &wqe->fcp_icmd.wqe_com, 1);
+				bf_set(wqe_ccp, &wqe->fcp_icmd.wqe_com,
+				       (iocbq->vmid_tag.cs_ctl_vmid));
+				/* Bit 0 must be 0 */
+			} else {
+				wqe128 = (union lpfc_wqe128 *)wqe;
+				bf_set(wqe_appid, &wqe->fcp_icmd.wqe_com, 1);
+				bf_set(wqe_wqes, &wqe128->fcp_icmd.wqe_com, 1);
+				wqe128->words[31] = iocbq->vmid_tag.app_id;
+			}
+		}
 		break;
 	case CMD_GEN_REQUEST64_CR:
 		/* For this command calculate the xmit length of the
-- 
2.26.2



From muneendra.kumar at broadcom.com  Wed Jan  6 17:00:24 2021
From: muneendra.kumar at broadcom.com (Muneendra)
Date: Thu,  7 Jan 2021 03:30:24 +0530
Subject: [PATCH v7 10/16] lpfc: vmid: Functions to manage vmids
In-Reply-To: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
References: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
Message-ID: <1609970430-19084-11-git-send-email-muneendra.kumar@broadcom.com>

From: Gaurav Srivastava <gaurav.srivastava at broadcom.com>

This patch contains the routines to save, retrieve and remove the vmids
from the data structure. A hash table is used to save the vmids and
the corresponding UUIDs associated with the application/VMs.

Reported-by: kernel test robot <lkp at intel.com>
Signed-off-by: Gaurav Srivastava  <gaurav.srivastava at broadcom.com>
Signed-off-by: James Smart <jsmart2021 at gmail.com>

---
v7:
No change

v6:
Added Forward declarations and functions to static

v5:
Changed Return code to non-numeric/Symbol

v4:
No change

v3:
No change

v2:
Ported the patch on top of 5.10/scsi-queue
---
 drivers/scsi/lpfc/lpfc_scsi.c | 148 ++++++++++++++++++++++++++++++++++
 1 file changed, 148 insertions(+)

diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index b79b6f03cdb6..53baee21e0f9 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -28,6 +28,7 @@
 #include <asm/unaligned.h>
 #include <linux/t10-pi.h>
 #include <linux/crc-t10dif.h>
+#include <linux/blk-cgroup.h>
 #include <net/checksum.h>
 
 #include <scsi/scsi.h>
@@ -86,6 +87,14 @@ static void
 lpfc_release_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_io_buf *psb);
 static int
 lpfc_prot_group_type(struct lpfc_hba *phba, struct scsi_cmnd *sc);
+static int
+lpfc_put_vmid_in_hashtable(struct lpfc_vport *vport, u32 hash,
+			   struct lpfc_vmid *vmp);
+static void lpfc_vmid_update_entry(struct lpfc_vport *vport, struct scsi_cmnd
+				   *cmd, struct lpfc_vmid *vmp,
+				   union lpfc_vmid_io_tag *tag);
+static void lpfc_vmid_assign_cs_ctl(struct lpfc_vport *vport,
+				    struct lpfc_vmid *vmid);
 
 static inline unsigned
 lpfc_cmd_blksize(struct scsi_cmnd *sc)
@@ -5131,6 +5140,145 @@ void lpfc_poll_timeout(struct timer_list *t)
 	}
 }
 
+/*
+ * lpfc_get_vmid_from_hastable - search the UUID in the hash table
+ * @vport: The virtual port for which this call is being executed.
+ * @hash: calculated hash value
+ * @buf: uuid associated with the VE
+ * Returns the vmid entry associated with the UUID
+ * Make sure to acquire the appropriate lock before invoking this routine.
+ */
+struct lpfc_vmid *lpfc_get_vmid_from_hastable(struct lpfc_vport *vport,
+					      u32 hash, u8 *buf)
+{
+	struct lpfc_vmid *vmp;
+	u16 count = 0;
+
+	while (count < LPFC_VMID_HASH_SIZE) {
+		vmp = vport->hash_table[hash];
+		if (vmp) {
+			if (strncmp(&vmp->host_vmid[0], buf, 16) == 0)
+				return vmp;
+		} else {
+			return NULL;
+		}
+		/* search the next available slot and continue till entry */
+		/* is found */
+		count++;
+		hash++;
+
+		/* or the end is reached */
+		if (hash == LPFC_VMID_HASH_SIZE)
+			hash = 0;
+	}
+	return NULL;
+}
+
+/*
+ * lpfc_put_vmid_from_hastable - put the VMID in the hash table
+ * @vport: The virtual port for which this call is being executed.
+ * @hash - calculated hash value
+ * @vmp: Pointer to a VMID entry representing a VM sending IO
+ *
+ * This routine will insert the newly acquired vmid entity in the hash table.
+ * Make sure to acquire the appropriate lock before invoking this routine.
+ */
+static int
+lpfc_put_vmid_in_hashtable(struct lpfc_vport *vport, u32 hash,
+			   struct lpfc_vmid *vmp)
+{
+	int count = 0;
+
+	while (count < LPFC_VMID_HASH_SIZE) {
+		if (!vport->hash_table[hash]) {
+			vport->hash_table[hash] = vmp;
+			vmp->hash_index = hash;
+			return FAILURE;
+		}
+		/* if the slot is already occupied, a collision has occurred. */
+		/* Store in the next available slot */
+		count++;
+		hash++;
+		/* table is full */
+		if (hash == LPFC_VMID_HASH_SIZE)
+			hash = 0;
+	}
+	return 0;
+}
+
+/*
+ * lpfc_vmid_hash_fn- creates a hash value of the UUID
+ * @uuid: uuid associated with the VE
+ * @len: length of the UUID
+ * Returns the calculated hash value
+ */
+int lpfc_vmid_hash_fn(char *vmid, int len)
+{
+	int c;
+	int hash = 0;
+
+	if (len == 0)
+		return 0;
+	while (len--) {
+		c = *vmid++;
+		if (c >= 'A' && c <= 'Z')
+			c += 'a' - 'A';
+
+		hash = (hash + (c << LPFC_VMID_HASH_SHIFT) +
+			(c >> LPFC_VMID_HASH_SHIFT)) * 19;
+	}
+
+	return hash & LPFC_VMID_HASH_MASK;
+}
+
+/*
+ * lpfc_vmid_update_entry - update the vmid entry in the hash table
+ * @vport: The virtual port for which this call is being executed.
+ * @cmd: address of scsi cmmd descriptor
+ * @vmp: Pointer to a VMID entry representing a VM sending IO
+ * @tag: VMID tag
+ */
+static void lpfc_vmid_update_entry(struct lpfc_vport *vport, struct scsi_cmnd
+				   *cmd, struct lpfc_vmid *vmp,
+				   union lpfc_vmid_io_tag *tag)
+{
+	u64 *lta;
+
+	if (vport->vmid_priority_tagging)
+		tag->cs_ctl_vmid = vmp->un.cs_ctl_vmid;
+	else
+		tag->app_id = vmp->un.app_id;
+
+	if (cmd->sc_data_direction == DMA_TO_DEVICE)
+		vmp->io_wr_cnt++;
+	else
+		vmp->io_rd_cnt++;
+
+	/* update the last access timestamp in the table */
+	lta = per_cpu_ptr(vmp->last_io_time, raw_smp_processor_id());
+	*lta = jiffies;
+}
+
+static void lpfc_vmid_assign_cs_ctl(struct lpfc_vport *vport,
+				    struct lpfc_vmid *vmid)
+{
+	u32 hash;
+	struct lpfc_vmid *pvmid;
+
+	if (vport->port_type == LPFC_PHYSICAL_PORT) {
+		vmid->un.cs_ctl_vmid = lpfc_vmid_get_cs_ctl(vport);
+	} else {
+		hash = lpfc_vmid_hash_fn(vmid->host_vmid, vmid->vmid_len);
+		pvmid =
+		    lpfc_get_vmid_from_hastable(vport->phba->pport, hash,
+						vmid->host_vmid);
+		if (!pvmid)
+			vmid->un.cs_ctl_vmid = pvmid->un.cs_ctl_vmid;
+		else
+			vmid->un.cs_ctl_vmid = lpfc_vmid_get_cs_ctl(vport);
+	}
+}
+
 /**
  * lpfc_queuecommand - scsi_host_template queuecommand entry point
  * @shost: kernel scsi host pointer.
-- 
2.26.2



From muneendra.kumar at broadcom.com  Wed Jan  6 17:00:23 2021
From: muneendra.kumar at broadcom.com (Muneendra)
Date: Thu,  7 Jan 2021 03:30:23 +0530
Subject: [PATCH v7 09/16] lpfc: vmid: Implements ELS commands for appid patch
In-Reply-To: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
References: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
Message-ID: <1609970430-19084-10-git-send-email-muneendra.kumar@broadcom.com>

From: Gaurav Srivastava <gaurav.srivastava at broadcom.com>

This patch implements ELS command like QFPA and UVEM for the priority
tagging appid support. Other supporting functions are also part of this
patch.

Reported-by: kernel test robot <lkp at intel.com>
Signed-off-by: Gaurav Srivastava  <gaurav.srivastava at broadcom.com>
Signed-off-by: James Smart <jsmart2021 at gmail.com>

---
v7:
No change

v6:
Added Forward declarations, static functions and
removed unused variables

v5:
Changed Return code to non-numeric/Symbol.
Addressed the review comments by Hannes

v4:
No change

v3:
No change

v2:
Ported the patch on top of 5.10/scsi-queue
---
 drivers/scsi/lpfc/lpfc_els.c | 369 ++++++++++++++++++++++++++++++++++-
 1 file changed, 362 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 96c087b8b474..dc88275db973 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -25,6 +25,7 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
+#include <linux/delay.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_device.h>
@@ -55,9 +56,15 @@ static int lpfc_issue_els_fdisc(struct lpfc_vport *vport,
 				struct lpfc_nodelist *ndlp, uint8_t retry);
 static int lpfc_issue_fabric_iocb(struct lpfc_hba *phba,
 				  struct lpfc_iocbq *iocb);
+static void lpfc_cmpl_els_uvem(struct lpfc_hba *, struct lpfc_iocbq *,
+			       struct lpfc_iocbq *);
 
 static int lpfc_max_els_tries = 3;
 
+static void lpfc_init_cs_ctl_bitmap(struct lpfc_vport *vport);
+static void lpfc_vmid_set_cs_ctl_range(struct lpfc_vport *vport, u32 min, u32 max);
+static void lpfc_vmid_put_cs_ctl(struct lpfc_vport *vport, u32 ctcl_vmid);
+
 /**
  * lpfc_els_chk_latt - Check host link attention event for a vport
  * @vport: pointer to a host virtual N_Port data structure.
@@ -312,12 +319,12 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
 	if (expectRsp) {
 		/* Xmit ELS command <elsCmd> to remote NPORT <did> */
 		lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
-				 "0116 Xmit ELS command x%x to remote "
-				 "NPORT x%x I/O tag: x%x, port state:x%x "
-				 "rpi x%x fc_flag:x%x\n",
+				 "0116 Xmit ELS command x%x to remote\n"
+				 "NPORT x%x I/O tag: x%x, port state:x%x\n"
+				 "rpi x%x fc_flag:x%x nlp_flag:x%x vport:x%p\n",
 				 elscmd, did, elsiocb->iotag,
 				 vport->port_state, ndlp->nlp_rpi,
-				 vport->fc_flag);
+				 vport->fc_flag, ndlp->nlp_flag, vport);
 	} else {
 		/* Xmit ELS response <elsCmd> to remote NPORT <did> */
 		lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
@@ -1111,12 +1118,16 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 
 	/* FLOGI completes successfully */
 	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
-			 "0101 FLOGI completes successfully, I/O tag:x%x, "
-			 "xri x%x Data: x%x x%x x%x x%x x%x %x\n",
+			 "0101 FLOGI completes successfully, I/O tag:x%x,\n"
+			 "xri x%x Data: x%x x%x x%x x%x x%x %x %x\n",
 			 cmdiocb->iotag, cmdiocb->sli4_xritag,
 			 irsp->un.ulpWord[4], sp->cmn.e_d_tov,
 			 sp->cmn.w2.r_a_tov, sp->cmn.edtovResolution,
-			 vport->port_state, vport->fc_flag);
+			 vport->port_state, vport->fc_flag,
+			 sp->cmn.priority_tagging);
+
+	if (sp->cmn.priority_tagging)
+		vport->vmid_flag |= LPFC_VMID_ISSUE_QFPA;
 
 	if (vport->port_state == LPFC_FLOGI) {
 		/*
@@ -1298,6 +1309,18 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 	if (sp->cmn.fcphHigh < FC_PH3)
 		sp->cmn.fcphHigh = FC_PH3;
 
+	/* to deterine if switch supports priority tagging */
+	if (phba->cfg_vmid_priority_tagging) {
+		sp->cmn.priority_tagging = 1;
+		/* lpfc_vmid_host_uuid is combination of wwpn and wwnn */
+		if (uuid_is_null((uuid_t *)vport->lpfc_vmid_host_uuid)) {
+			memcpy(vport->lpfc_vmid_host_uuid, phba->wwpn,
+			       sizeof(phba->wwpn));
+			memcpy(&vport->lpfc_vmid_host_uuid[8], phba->wwnn,
+			       sizeof(phba->wwnn));
+		}
+	}
+
 	if  (phba->sli_rev == LPFC_SLI_REV4) {
 		if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
 		    LPFC_SLI_INTF_IF_TYPE_0) {
@@ -1928,6 +1951,7 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 	struct lpfc_nodelist *ndlp, *free_ndlp;
 	struct lpfc_dmabuf *prsp;
 	int disc;
+	struct serv_parm *sp = NULL;
 
 	/* we pass cmdiocb to state machine which needs rspiocb as well */
 	cmdiocb->context_un.rsp_iocb = rspiocb;
@@ -2018,6 +2042,23 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 				   cmdiocb->context2)->list.next,
 				  struct lpfc_dmabuf, list);
 		ndlp = lpfc_plogi_confirm_nport(phba, prsp->virt, ndlp);
+
+		sp = (struct serv_parm *)((u8 *)prsp->virt +
+					  sizeof(u32));
+
+		ndlp->vmid_support = 0;
+		if ((phba->cfg_vmid_app_header && sp->cmn.app_hdr_support) ||
+		    (phba->cfg_vmid_priority_tagging &&
+		     sp->cmn.priority_tagging)) {
+			lpfc_printf_log(phba, KERN_DEBUG, LOG_ELS,
+					"4018 app_hdr_support %d tagging %d DID x%x",
+					sp->cmn.app_hdr_support,
+					sp->cmn.priority_tagging,
+					ndlp->nlp_DID);
+			/* if the dest port supports VMID, mark it in ndlp */
+			ndlp->vmid_support = 1;
+		}
+
 		lpfc_disc_state_machine(vport, ndlp, cmdiocb,
 					NLP_EVT_CMPL_PLOGI);
 	}
@@ -2142,6 +2183,14 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
 	memset(sp->un.vendorVersion, 0, sizeof(sp->un.vendorVersion));
 	sp->cmn.bbRcvSizeMsb &= 0xF;
 
+	/* check if the destination port supports VMID */
+	ndlp->vmid_support = 0;
+	if (vport->vmid_priority_tagging)
+		sp->cmn.priority_tagging = 1;
+	else if (phba->cfg_vmid_app_header &&
+		 bf_get(lpfc_ftr_ashdr, &phba->sli4_hba.sli4_flags))
+		sp->cmn.app_hdr_support = 1;
+
 	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
 		"Issue PLOGI:     did:x%x",
 		did, 0, 0);
@@ -10306,3 +10355,309 @@ lpfc_sli_abts_recover_port(struct lpfc_vport *vport,
 	lpfc_unreg_rpi(vport, ndlp);
 }
 
+static void lpfc_init_cs_ctl_bitmap(struct lpfc_vport *vport)
+{
+	bitmap_zero(vport->vmid_priority_range, LPFC_VMID_MAX_PRIORITY_RANGE);
+}
+
+static void
+lpfc_vmid_set_cs_ctl_range(struct lpfc_vport *vport, u32 min, u32 max)
+{
+	u32 i;
+
+	if ((min > max) || (max > LPFC_VMID_MAX_PRIORITY_RANGE))
+		return;
+
+	for (i = min; i <= max; i++)
+		set_bit(i, vport->vmid_priority_range);
+}
+
+static void lpfc_vmid_put_cs_ctl(struct lpfc_vport *vport, u32 ctcl_vmid)
+{
+	set_bit(ctcl_vmid, vport->vmid_priority_range);
+}
+
+u32 lpfc_vmid_get_cs_ctl(struct lpfc_vport *vport)
+{
+	u32 i;
+
+	i = find_first_bit(vport->vmid_priority_range,
+			   LPFC_VMID_MAX_PRIORITY_RANGE);
+
+	if (i == LPFC_VMID_MAX_PRIORITY_RANGE)
+		return 0;
+
+	clear_bit(i, vport->vmid_priority_range);
+	return i;
+}
+
+#define MAX_PRIORITY_DESC	255
+
+static void
+lpfc_cmpl_els_qfpa(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+		   struct lpfc_iocbq *rspiocb)
+{
+	struct lpfc_vport *vport = cmdiocb->vport;
+	struct priority_range_desc *desc;
+	struct lpfc_dmabuf *prsp = NULL;
+	struct lpfc_vmid_priority_range *vmid_range = NULL;
+	u32 *data;
+	struct lpfc_dmabuf *dmabuf = cmdiocb->context2;
+	IOCB_t *irsp = &rspiocb->iocb;
+	u8 *pcmd;
+	u32 len, i;
+	struct lpfc_nodelist *ndlp = NULL;
+
+	prsp = list_get_first(&dmabuf->list, struct lpfc_dmabuf, list);
+	if (!prsp)
+		goto out;
+
+	ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+	pcmd = prsp->virt;
+	data = (u32 *)pcmd;
+	if (data[0] == ELS_CMD_LS_RJT) {
+		lpfc_printf_vlog(vport, KERN_WARNING, LOG_SLI,
+				 "6528 QFPA LS_RJT %x  %x ", data[0], data[1]);
+		goto out;
+	}
+	if (irsp->ulpStatus) {
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_SLI,
+				 "6529 QFPA failed with status %x  %x ",
+				 irsp->ulpStatus, irsp->un.ulpWord[4]);
+		goto out;
+	}
+
+	if (!vport->qfpa_res) {
+		vport->qfpa_res = kmalloc(FCELSSIZE, GFP_KERNEL);
+		if (!vport->qfpa_res)
+			goto out;
+		memset(vport->qfpa_res, 0, FCELSSIZE);
+	}
+
+	len = *((u32 *)(pcmd + 4));
+	len = be32_to_cpu(len);
+	memcpy(vport->qfpa_res, pcmd, len + 8);
+	len = len / LPFC_PRIORITY_RANGE_DESC_SIZE;
+
+	desc = (struct priority_range_desc *)(pcmd + 8);
+	vmid_range = vport->vmid_priority.vmid_range;
+	if (!vmid_range) {
+		vmid_range = kmalloc_array(MAX_PRIORITY_DESC,
+					   sizeof
+					   (struct lpfc_vmid_priority_range),
+					   GFP_KERNEL);
+		if (!vmid_range)
+			goto out;
+		memset(vmid_range, 0, MAX_PRIORITY_DESC *
+		       sizeof(struct lpfc_vmid_priority_range));
+		vport->vmid_priority.vmid_range = vmid_range;
+	}
+	vport->vmid_priority.num_descriptors = len;
+
+	for (i = 0; i < len; i++, vmid_range++, desc++) {
+		lpfc_printf_vlog(vport, KERN_DEBUG, LOG_ELS,
+				 "6539 vmid values low=%d, high=%d, qos=%d,\n"
+				 " local ve id=%d\n", desc->lo_range,
+				 desc->hi_range, desc->qos_priority,
+				 desc->local_ve_id);
+
+		vmid_range->low = desc->lo_range << 1;
+		if (desc->local_ve_id == QFPA_ODD_ONLY)
+			vmid_range->low++;
+		if (desc->qos_priority)
+			vport->vmid_flag |= LPFC_VMID_QOS_ENABLED;
+		vmid_range->qos = desc->qos_priority;
+
+		vmid_range->high = desc->hi_range << 1;
+		if ((desc->local_ve_id == QFPA_ODD_ONLY) ||
+		    (desc->local_ve_id == QFPA_EVEN_ODD))
+			vmid_range->high++;
+	}
+	lpfc_init_cs_ctl_bitmap(vport);
+	for (i = 0; i < vport->vmid_priority.num_descriptors; i++) {
+		lpfc_vmid_set_cs_ctl_range(vport,
+				vport->vmid_priority.vmid_range[i].low,
+				vport->vmid_priority.vmid_range[i].high);
+	}
+
+	vport->vmid_flag |= LPFC_VMID_QFPA_CMPL;
+ out:
+	lpfc_els_free_iocb(phba, cmdiocb);
+	if (ndlp)
+		lpfc_nlp_put(ndlp);
+}
+
+int lpfc_issue_els_qfpa(struct lpfc_vport *vport)
+{
+	struct lpfc_hba *phba = vport->phba;
+	struct lpfc_nodelist *ndlp;
+	struct lpfc_iocbq *elsiocb;
+	u8 *pcmd;
+	int ret;
+
+	ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
+	if (!ndlp || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)
+		return FAILURE;
+
+	if (!ndlp)
+		return FAILURE;
+
+	elsiocb = lpfc_prep_els_iocb(vport, 1, LPFC_QFPA_SIZE, 2, ndlp,
+				     ndlp->nlp_DID, ELS_CMD_QFPA);
+	if (!elsiocb)
+		return FAILURE;
+
+	pcmd = (u8 *)(((struct lpfc_dmabuf *)elsiocb->context2)->virt);
+
+	*((u32 *)(pcmd)) = ELS_CMD_QFPA;
+	pcmd += 4;
+
+	elsiocb->iocb_cmpl = lpfc_cmpl_els_qfpa;
+
+	elsiocb->context1 = lpfc_nlp_get(ndlp);
+	if (!elsiocb->context1)
+		return FAILURE;
+
+	ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 2);
+	if (ret != IOCB_SUCCESS) {
+		lpfc_nlp_put(ndlp);
+		lpfc_els_free_iocb(phba, elsiocb);
+		return FAILURE;
+	}
+	vport->vmid_flag &= ~LPFC_VMID_QOS_ENABLED;
+	return 0;
+}
+
+int
+lpfc_vmid_uvem(struct lpfc_vport *vport,
+	       struct lpfc_vmid *vmid, bool instantiated)
+{
+	struct lpfc_vem_id_desc *vem_id_desc;
+	struct lpfc_nodelist *ndlp;
+	struct lpfc_iocbq *elsiocb;
+	struct instantiated_ve_desc *inst_desc;
+	struct lpfc_vmid_context *vmid_context;
+	u8 *pcmd;
+	u32 *len;
+	int ret = 0;
+
+	ndlp = lpfc_findnode_did(vport, Fabric_DID);
+	if (!ndlp || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)
+		return FAILURE;
+
+	vmid_context = kmalloc(sizeof(*vmid_context), GFP_KERNEL);
+	if (!vmid_context)
+		return FAILURE;
+	elsiocb = lpfc_prep_els_iocb(vport, 1, LPFC_UVEM_SIZE, 2,
+				     ndlp, Fabric_DID, ELS_CMD_UVEM);
+	if (!elsiocb)
+		goto out;
+
+	lpfc_printf_vlog(vport, KERN_DEBUG, LOG_ELS,
+			 "3427 %s %d", vmid->host_vmid, instantiated);
+	vmid_context->vmp = vmid;
+	vmid_context->nlp = ndlp;
+	vmid_context->instantiated = instantiated;
+	elsiocb->vmid_tag.vmid_context = vmid_context;
+	pcmd = (u8 *)(((struct lpfc_dmabuf *)elsiocb->context2)->virt);
+
+	if (uuid_is_null((uuid_t *)vport->lpfc_vmid_host_uuid))
+		memcpy(vport->lpfc_vmid_host_uuid, vmid->host_vmid,
+		       LPFC_COMPRESS_VMID_SIZE);
+
+	*((u32 *)(pcmd)) = ELS_CMD_UVEM;
+	len = (u32 *)(pcmd + 4);
+	*len = cpu_to_be32(LPFC_UVEM_SIZE - 8);
+
+	vem_id_desc = (struct lpfc_vem_id_desc *)(pcmd + 8);
+	vem_id_desc->tag = be32_to_cpu(VEM_ID_DESC_TAG);
+	vem_id_desc->length = be32_to_cpu(LPFC_UVEM_VEM_ID_DESC_SIZE);
+	memcpy(vem_id_desc->vem_id, vport->lpfc_vmid_host_uuid,
+	       LPFC_COMPRESS_VMID_SIZE);
+
+	inst_desc = (struct instantiated_ve_desc *)(pcmd + 32);
+	inst_desc->tag = be32_to_cpu(INSTANTIATED_VE_DESC_TAG);
+	inst_desc->length = be32_to_cpu(LPFC_UVEM_VE_MAP_DESC_SIZE);
+	memcpy(inst_desc->global_vem_id, vmid->host_vmid,
+	       LPFC_COMPRESS_VMID_SIZE);
+
+	bf_set(lpfc_instantiated_nport_id, inst_desc, vport->fc_myDID);
+	bf_set(lpfc_instantiated_local_id, inst_desc,
+	       vmid->un.cs_ctl_vmid);
+	if (instantiated) {
+		inst_desc->tag = be32_to_cpu(INSTANTIATED_VE_DESC_TAG);
+	} else {
+		inst_desc->tag = be32_to_cpu(DEINSTANTIATED_VE_DESC_TAG);
+		lpfc_vmid_put_cs_ctl(vport, vmid->un.cs_ctl_vmid);
+	}
+	inst_desc->word6 = cpu_to_be32(inst_desc->word6);
+
+	elsiocb->iocb_cmpl = lpfc_cmpl_els_uvem;
+
+	elsiocb->context1 = lpfc_nlp_get(ndlp);
+	if (!elsiocb->context1)
+		return FAILURE;
+
+	ret = lpfc_sli_issue_iocb(vport->phba, LPFC_ELS_RING, elsiocb, 0);
+	if (ret != IOCB_SUCCESS) {
+		lpfc_els_free_iocb(vport->phba, elsiocb);
+		goto out;
+	}
+
+	return 0;
+ out:
+	kfree(vmid_context);
+	return FAILURE;
+}
+
+static void
+lpfc_cmpl_els_uvem(struct lpfc_hba *phba, struct lpfc_iocbq *icmdiocb,
+		   struct lpfc_iocbq *rspiocb)
+{
+	struct lpfc_vport *vport = icmdiocb->vport;
+	struct lpfc_dmabuf *prsp = NULL;
+	struct lpfc_vmid_context *vmid_context =
+	    icmdiocb->vmid_tag.vmid_context;
+	struct lpfc_nodelist *ndlp = icmdiocb->context1;
+	u8 *pcmd;
+	u32 *data;
+	IOCB_t *irsp = &rspiocb->iocb;
+	struct lpfc_dmabuf *dmabuf = icmdiocb->context2;
+	struct lpfc_vmid *vmid;
+
+	vmid = vmid_context->vmp;
+	if (!ndlp || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)
+		ndlp = NULL;
+
+	prsp = list_get_first(&dmabuf->list, struct lpfc_dmabuf, list);
+	if (!prsp)
+		goto out;
+	pcmd = prsp->virt;
+	data = (u32 *)pcmd;
+	if (data[0] == ELS_CMD_LS_RJT) {
+		lpfc_printf_vlog(vport, KERN_WARNING, LOG_SLI,
+				 "4532 UVEM LS_RJT %x %x ", data[0], data[1]);
+		goto out;
+	}
+	if (irsp->ulpStatus) {
+		lpfc_printf_vlog(vport, KERN_WARNING, LOG_SLI,
+				 "4533 UVEM error status %x: %x ",
+				 irsp->ulpStatus, irsp->un.ulpWord[4]);
+		goto out;
+	}
+	spin_lock(&phba->hbalock);
+	/* Set IN USE flag */
+	vport->vmid_flag |= LPFC_VMID_IN_USE;
+	phba->pport->vmid_flag |= LPFC_VMID_IN_USE;
+	spin_unlock(&phba->hbalock);
+
+	if (vmid_context->instantiated) {
+		vmid->flag |= LPFC_VMID_REGISTERED;
+		vmid->flag &= ~LPFC_VMID_REQ_REGISTER;
+	}
+
+ out:
+	kfree(vmid_context);
+	lpfc_els_free_iocb(phba, icmdiocb);
+	lpfc_nlp_put(ndlp);
+}
-- 
2.26.2



From muneendra.kumar at broadcom.com  Wed Jan  6 17:00:30 2021
From: muneendra.kumar at broadcom.com (Muneendra)
Date: Thu,  7 Jan 2021 03:30:30 +0530
Subject: [PATCH v7 16/16] scsi: Made changes in Kconfig to select
 BLK_CGROUP_FC_APPID
In-Reply-To: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
References: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
Message-ID: <1609970430-19084-17-git-send-email-muneendra.kumar@broadcom.com>

Added a new config FC_APPID to select BLK_CGROUP_FC_APPID
which Enable support to track FC io Traffic.

Reported-by: kernel test robot <lkp at intel.com>
Signed-off-by: Muneendra <muneendra.kumar at broadcom.com>

---
v7:
Modified the Kconfig comments

v6:
Modified the Kconfig comments

v5:
No change

v4:
Addressed the error reported by kernel test robot

v3:
New patch
---
 drivers/scsi/Kconfig | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 701b61ec76ee..500f88ce29e3 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -235,6 +235,19 @@ config SCSI_FC_ATTRS
 	  each attached FiberChannel device to sysfs, say Y.
 	  Otherwise, say N.
 
+config FC_APPID
+	bool "Enable support to track FC I/O Traffic"
+	depends on BLOCK && BLK_CGROUP
+	depends on SCSI
+	select BLK_CGROUP_FC_APPID
+	default y
+	help
+	  If you say Y here, it enables the support to track
+	  FC I/O traffic over fabric. It enables the Fabric and the
+	  storage targets to identify, monitor, and handle FC traffic
+	  based on VM tags by inserting application specific
+	  identification into the FC frame.
+
 config SCSI_ISCSI_ATTRS
 	tristate "iSCSI Transport Attributes"
 	depends on SCSI && NET
-- 
2.26.2



From muneendra.kumar at broadcom.com  Wed Jan  6 17:00:28 2021
From: muneendra.kumar at broadcom.com (Muneendra)
Date: Thu,  7 Jan 2021 03:30:28 +0530
Subject: [PATCH v7 14/16] lpfc: vmid: Adding qfpa and vmid timeout check in
 worker thread
In-Reply-To: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
References: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
Message-ID: <1609970430-19084-15-git-send-email-muneendra.kumar@broadcom.com>

From: Gaurav Srivastava <gaurav.srivastava at broadcom.com>

This patch add the periodic check for issuing of qfpa command and vmid
timeout in the worker thread. The inactivity timeout check is added via
the timer function.

Reported-by: kernel test robot <lkp at intel.com>
Signed-off-by: Gaurav Srivastava  <gaurav.srivastava at broadcom.com>
Signed-off-by: James Smart <jsmart2021 at gmail.com>

---
v7:
No change

v6:
Added Forward declarations and removed unused variable

v5:
No change

v4:
No change

v3:
No change

v2:
Ported the patch on top of 5.10/scsi-queue
---
 drivers/scsi/lpfc/lpfc_hbadisc.c | 43 ++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index ed2d65cfd3e3..46dad0780368 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -73,6 +73,7 @@ static void lpfc_unregister_fcfi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
 static int lpfc_fcf_inuse(struct lpfc_hba *);
 static void lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *);
 static void lpfc_check_inactive_vmid(struct lpfc_hba *phba);
+static void lpfc_check_vmid_qfpa_issue(struct lpfc_hba *phba);
 
 /* The source of a terminate rport I/O is either a dev_loss_tmo
  * event or a call to fc_remove_host.  While the rport should be
@@ -429,6 +430,32 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
 	return fcf_inuse;
 }
 
+static void lpfc_check_vmid_qfpa_issue(struct lpfc_hba *phba)
+{
+	struct lpfc_vport *vport;
+	struct lpfc_vport **vports;
+	int i;
+
+	vports = lpfc_create_vport_work_array(phba);
+	if (!vports)
+		return;
+
+	for (i = 0; i <= phba->max_vports; i++) {
+		if ((!vports[i]) && (i == 0))
+			vport = phba->pport;
+		else
+			vport = vports[i];
+		if (!vport)
+			break;
+
+		if (vport->vmid_flag & LPFC_VMID_ISSUE_QFPA) {
+			lpfc_issue_els_qfpa(vport);
+			vport->vmid_flag &= ~LPFC_VMID_ISSUE_QFPA;
+		}
+	}
+	lpfc_destroy_vport_work_array(phba, vports);
+}
+
 /**
  * lpfc_sli4_post_dev_loss_tmo_handler - SLI4 post devloss timeout handler
  * @phba: Pointer to hba context object.
@@ -749,6 +776,22 @@ lpfc_work_done(struct lpfc_hba *phba)
 	if (ha_copy & HA_LATT)
 		lpfc_handle_latt(phba);
 
+	/* Handle VMID Events */
+	if (lpfc_is_vmid_enabled(phba)) {
+		if (phba->pport->work_port_events &
+		    WORKER_CHECK_VMID_ISSUE_QFPA) {
+			lpfc_check_vmid_qfpa_issue(phba);
+			phba->pport->work_port_events &=
+				~WORKER_CHECK_VMID_ISSUE_QFPA;
+		}
+		if (phba->pport->work_port_events &
+		    WORKER_CHECK_INACTIVE_VMID) {
+			lpfc_check_inactive_vmid(phba);
+			phba->pport->work_port_events &=
+			    ~WORKER_CHECK_INACTIVE_VMID;
+		}
+	}
+
 	/* Process SLI4 events */
 	if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) {
 		if (phba->hba_flag & HBA_RRQ_ACTIVE)
-- 
2.26.2



From muneendra.kumar at broadcom.com  Wed Jan  6 17:00:27 2021
From: muneendra.kumar at broadcom.com (Muneendra)
Date: Thu,  7 Jan 2021 03:30:27 +0530
Subject: [PATCH v7 13/16] lpfc: vmid: Timeout implementation for vmid
In-Reply-To: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
References: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
Message-ID: <1609970430-19084-14-git-send-email-muneendra.kumar@broadcom.com>

From: Gaurav Srivastava <gaurav.srivastava at broadcom.com>

This patch implements the timeout functionality for the vmid. After the
set time period of inactivity, the vmid is deregistered from the switch.

Reported-by: kernel test robot <lkp at intel.com>
Signed-off-by: Gaurav Srivastava  <gaurav.srivastava at broadcom.com>
Signed-off-by: James Smart <jsmart2021 at gmail.com>

---
v7:
No change

v6:
Added Forward declarations

v5:
No change

v4:
No change

v3:
No change

v2:
Ported the patch on top of 5.10/scsi-queue
---
 drivers/scsi/lpfc/lpfc_hbadisc.c | 110 +++++++++++++++++++++++++++++++
 drivers/scsi/lpfc/lpfc_init.c    |  40 +++++++++++
 2 files changed, 150 insertions(+)

diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 2b6b5fc671fe..ed2d65cfd3e3 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -72,6 +72,7 @@ static void lpfc_disc_flush_list(struct lpfc_vport *vport);
 static void lpfc_unregister_fcfi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
 static int lpfc_fcf_inuse(struct lpfc_hba *);
 static void lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *);
+static void lpfc_check_inactive_vmid(struct lpfc_hba *phba);
 
 /* The source of a terminate rport I/O is either a dev_loss_tmo
  * event or a call to fc_remove_host.  While the rport should be
@@ -229,6 +230,115 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
 	return;
 }
 
+/**
+ * lpfc_check_inactive_vmid_one - VMID inactivity checker for a vport
+ * @vport: Pointer to vport context object.
+ *
+ * This function checks for idle vmid entries related to a particular vport. If
+ * found unused/idle, it frees them accordingly.
+ **/
+static void lpfc_check_inactive_vmid_one(struct lpfc_vport *vport)
+{
+	u16 i, keep;
+	u32 difftime = 0, r;
+	u64 *lta;
+	int cpu;
+
+	write_lock(&vport->vmid_lock);
+
+	if (!vport->cur_vmid_cnt)
+		goto out;
+
+	/* iterate through the table */
+	for (i = 0; i < LPFC_VMID_HASH_SIZE; ++i) {
+		if (vport->hash_table[i] && (vport->hash_table[i]->flag &
+					     LPFC_VMID_REGISTERED)) {
+			/* check if the particular vmid is in use */
+			/* for all available per cpu variable */
+			for_each_possible_cpu(cpu) {
+				/* if last access time is less than timeout */
+				lta = per_cpu_ptr(
+					vport->hash_table[i]->last_io_time,
+					cpu);
+				if (!lta)
+					continue;
+				difftime = (jiffies) - (*lta);
+				if ((vport->vmid_inactivity_timeout *
+				     JIFFIES_PER_HR) > difftime) {
+					keep = 1;
+					break;
+				}
+			}
+
+			/* if none of the cpus have been used by the vm, */
+			/*  remove the entry if already registered */
+			if (!keep) {
+				/* mark the entry for deregistration */
+				vport->hash_table[i]->flag =
+					LPFC_VMID_DE_REGISTER;
+				write_unlock(&vport->vmid_lock);
+				if (vport->vmid_priority_tagging)
+					r = lpfc_vmid_uvem(vport,
+							   vport->hash_table[i],
+							   false);
+				else
+					r = lpfc_vmid_cmd(vport,
+							  SLI_CTAS_DAPP_IDENT,
+							  vport->hash_table[i]);
+
+				/* decrement number of active vms and mark */
+				/* entry in slot as free */
+				write_lock(&vport->vmid_lock);
+				if (!r) {
+					struct lpfc_vmid *ht =
+							vport->hash_table[i];
+					vport->cur_vmid_cnt--;
+					ht->flag = LPFC_VMID_SLOT_FREE;
+					free_percpu(ht->last_io_time);
+					ht->last_io_time = NULL;
+					vport->hash_table[i] = NULL;
+				}
+			}
+		}
+		keep = 0;
+	}
+ out:
+	write_unlock(&vport->vmid_lock);
+}
+
+/**
+ * lpfc_check_inactive_vmid - VMID inactivity checker
+ * @phba: Pointer to hba context object.
+ *
+ * This function is called from the worker thread to determine if an entry in
+ * the vmid table can be released since there was no IO activity seen from that
+ * particular VM for the specified time. When this happens, the entry in the
+ * table is released and also the resources on the switch cleared.
+ **/
+
+static void lpfc_check_inactive_vmid(struct lpfc_hba *phba)
+{
+	struct lpfc_vport *vport;
+	struct lpfc_vport **vports;
+	int i;
+
+	vports = lpfc_create_vport_work_array(phba);
+	if (!vports)
+		return;
+
+	for (i = 0; i <= phba->max_vports; i++) {
+		if ((!vports[i]) && (i == 0))
+			vport = phba->pport;
+		else
+			vport = vports[i];
+		if (!vport)
+			break;
+
+		lpfc_check_inactive_vmid_one(vport);
+	}
+	lpfc_destroy_vport_work_array(phba, vports);
+}
+
 /**
  * lpfc_dev_loss_tmo_handler - Remote node devloss timeout handler
  * @ndlp: Pointer to remote node object.
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index dea423bc1293..800164390879 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -4812,6 +4812,42 @@ lpfc_sli4_fcf_redisc_wait_tmo(struct timer_list *t)
 	lpfc_worker_wake_up(phba);
 }
 
+/**
+ * lpfc_vmid_poll - VMID timeout detection
+ * @ptr: Map to lpfc_hba data structure pointer.
+ *
+ * This routine is invoked when there is no IO on by a VM for the specified
+ * amount of time. When this situation is detected, the VMID has to be
+ * deregistered from the switch and all the local resources freed. The VMID
+ * will be reassigned to the VM once the IO begins.
+ **/
+static void
+lpfc_vmid_poll(struct timer_list *t)
+{
+	struct lpfc_hba *phba = from_timer(phba, t, inactive_vmid_poll);
+	u32 wake_up = 0;
+
+	/* check if there is a need to issue QFPA */
+	if (phba->pport->vmid_priority_tagging) {
+		wake_up = 1;
+		phba->pport->work_port_events |= WORKER_CHECK_VMID_ISSUE_QFPA;
+	}
+
+	/* Is the vmid inactivity timer enabled */
+	if (phba->pport->vmid_inactivity_timeout ||
+	    phba->pport->load_flag & FC_DEREGISTER_ALL_APP_ID) {
+		wake_up = 1;
+		phba->pport->work_port_events |= WORKER_CHECK_INACTIVE_VMID;
+	}
+
+	if (wake_up)
+		lpfc_worker_wake_up(phba);
+
+	/* restart the timer for the next iteration */
+	mod_timer(&phba->inactive_vmid_poll, jiffies + msecs_to_jiffies(1000 *
+							LPFC_VMID_TIMER));
+}
+
 /**
  * lpfc_sli4_parse_latt_fault - Parse sli4 link-attention link fault code
  * @phba: pointer to lpfc hba data structure.
@@ -6658,6 +6694,10 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
 	phba->hbqs[LPFC_ELS_HBQ].hbq_alloc_buffer = lpfc_sli4_rb_alloc;
 	phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer = lpfc_sli4_rb_free;
 
+	/* for VMID idle timeout if VMID is enabled */
+	if (lpfc_is_vmid_enabled(phba))
+		timer_setup(&phba->inactive_vmid_poll, lpfc_vmid_poll, 0);
+
 	/*
 	 * Initialize the SLI Layer to run with lpfc SLI4 HBAs.
 	 */
-- 
2.26.2



From muneendra.kumar at broadcom.com  Wed Jan  6 17:00:29 2021
From: muneendra.kumar at broadcom.com (Muneendra)
Date: Thu,  7 Jan 2021 03:30:29 +0530
Subject: [PATCH v7 15/16] lpfc: vmid: Introducing vmid in io path.
In-Reply-To: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
References: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
Message-ID: <1609970430-19084-16-git-send-email-muneendra.kumar@broadcom.com>

From: Gaurav Srivastava <gaurav.srivastava at broadcom.com>

The patch introduces the vmid in the io path. It checks if the vmid is
enabled and if io belongs to a vm or not and acts accordingly. Other
supporing APIs are also included in the patch.

Signed-off-by: Gaurav Srivastava  <gaurav.srivastava at broadcom.com>
Signed-off-by: James Smart <jsmart2021 at gmail.com>

---
v7:
No change

v6:
No change

v5:
No change

v4:
No change

v3:
Replaced blkcg_get_app_identifier with blkcg_get_fc_appid

v2:
Ported the patch on top of 5.10/scsi-queue
Added a fix for issuing QFPA command which was not included in the
last submit
---
 drivers/scsi/lpfc/lpfc_scsi.c | 165 ++++++++++++++++++++++++++++++++++
 1 file changed, 165 insertions(+)

diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 53baee21e0f9..21f151492a18 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -5279,6 +5279,151 @@ static void lpfc_vmid_assign_cs_ctl(struct lpfc_vport *vport,
 	}
 }
 
+/*
+ * lpfc_vmid_get_appid- get the vmid associated with the uuid
+ * @vport: The virtual port for which this call is being executed.
+ * @uuid: uuid associated with the VE
+ * @cmd: address of scsi cmmd descriptor
+ * @tag: VMID tag
+ * Returns status of the function
+ */
+static int lpfc_vmid_get_appid(struct lpfc_vport *vport, char *uuid, struct
+			       scsi_cmnd * cmd, union lpfc_vmid_io_tag *tag)
+{
+	struct lpfc_vmid *vmp = NULL;
+	int hash, len, rc = 1, i;
+	u8 pending = 0;
+
+	/* check if QFPA is complete */
+	if (lpfc_vmid_is_type_priority_tag(vport) && !(vport->vmid_flag &
+	      LPFC_VMID_QFPA_CMPL)) {
+		vport->work_port_events |= WORKER_CHECK_VMID_ISSUE_QFPA;
+		return FAILURE;
+	}
+
+	/* search if the uuid has already been mapped to the vmid */
+	len = strlen(uuid);
+	hash = lpfc_vmid_hash_fn(uuid, len);
+
+	/* search for the VMID in the table */
+	read_lock(&vport->vmid_lock);
+	vmp = lpfc_get_vmid_from_hastable(vport, hash, uuid);
+	read_unlock(&vport->vmid_lock);
+
+	/* if found, check if its already registered  */
+	if (vmp  && vmp->flag & LPFC_VMID_REGISTERED) {
+		lpfc_vmid_update_entry(vport, cmd, vmp, tag);
+		rc = 0;
+	} else if (vmp && (vmp->flag & LPFC_VMID_REQ_REGISTER ||
+			   vmp->flag & LPFC_VMID_DE_REGISTER)) {
+		/* else if register or dereg request has already been sent */
+		/* Hence vmid tag will not be added for this IO */
+		rc = 1;
+	} else {
+		/* else, start the process to obtain one as per the */
+		/* switch connected */
+		write_lock(&vport->vmid_lock);
+		vmp = lpfc_get_vmid_from_hastable(vport, hash, uuid);
+
+		/* while the read lock was released, in case the entry was */
+		/* added by other context or is in process of being added */
+		if (vmp && vmp->flag & LPFC_VMID_REGISTERED) {
+			lpfc_vmid_update_entry(vport, cmd, vmp, tag);
+			write_unlock(&vport->vmid_lock);
+			return 0;
+		} else if (vmp && vmp->flag & LPFC_VMID_REQ_REGISTER) {
+			write_unlock(&vport->vmid_lock);
+			return FAILURE;
+		}
+
+		/* else search and allocate a free slot in the hash table */
+		if (vport->cur_vmid_cnt < vport->max_vmid) {
+			for (i = 0; i < vport->max_vmid; ++i) {
+				vmp = vport->vmid + i;
+				if (vmp->flag == LPFC_VMID_SLOT_FREE) {
+					vmp = vport->vmid + i;
+					break;
+				}
+			}
+		} else {
+			write_unlock(&vport->vmid_lock);
+			return FAILURE;
+		}
+
+		if (vmp && (vmp->flag == LPFC_VMID_SLOT_FREE)) {
+			vmp->vmid_len = len;
+
+			/* Add the vmid and register  */
+			memcpy(vmp->host_vmid, uuid, vmp->vmid_len);
+			vmp->io_rd_cnt = 0;
+			vmp->io_wr_cnt = 0;
+			vmp->flag = LPFC_VMID_SLOT_USED;
+			lpfc_put_vmid_in_hashtable(vport, hash, vmp);
+
+			vmp->delete_inactive =
+			    vport->vmid_inactivity_timeout ? 1 : 0;
+
+			/* if type priority tag, get next available vmid */
+			if (lpfc_vmid_is_type_priority_tag(vport))
+				lpfc_vmid_assign_cs_ctl(vport, vmp);
+
+			/* allocate the per cpu variable for holding */
+			/* the last access time stamp only if vmid is enabled */
+			if (!vmp->last_io_time)
+				vmp->last_io_time =
+				    __alloc_percpu(sizeof(u64),
+						   __alignof__(struct
+							       lpfc_vmid));
+
+			/* registration pending */
+			pending = 1;
+			rc = 1;
+		}
+		write_unlock(&vport->vmid_lock);
+
+		/* complete transaction with switch */
+		if (pending) {
+			if (lpfc_vmid_is_type_priority_tag(vport))
+				rc = lpfc_vmid_uvem(vport, vmp, true);
+			else
+				rc = lpfc_vmid_cmd(vport,
+						   SLI_CTAS_RAPP_IDENT,
+						   vmp);
+			if (!rc) {
+				write_lock(&vport->vmid_lock);
+				vport->cur_vmid_cnt++;
+				vmp->flag |= LPFC_VMID_REQ_REGISTER;
+				write_unlock(&vport->vmid_lock);
+			}
+		}
+
+		/* finally, enable the idle timer once */
+		if (!(vport->phba->pport->vmid_flag & LPFC_VMID_TIMER_ENBLD)) {
+			mod_timer(&vport->phba->inactive_vmid_poll,
+				  jiffies +
+				  msecs_to_jiffies(1000 * LPFC_VMID_TIMER));
+			vport->phba->pport->vmid_flag |= LPFC_VMID_TIMER_ENBLD;
+		}
+	}
+	return rc;
+}
+
+/*
+ * lpfc_is_command_vm_io - get the uuid from blk cgroup
+ * @cmd:Pointer to scsi_cmnd data structure
+ * Returns uuid if present if not null
+ */
+static char *lpfc_is_command_vm_io(struct scsi_cmnd *cmd)
+{
+	char *uuid = NULL;
+
+	if (cmd->request) {
+		if (cmd->request->bio)
+			uuid = blkcg_get_fc_appid(cmd->request->bio);
+	}
+	return uuid;
+}
+
 /**
  * lpfc_queuecommand - scsi_host_template queuecommand entry point
  * @shost: kernel scsi host pointer.
@@ -5304,6 +5449,7 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd)
 	int err, idx;
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
 	uint64_t start = 0L;
+	u8 *uuid = NULL;
 
 	if (phba->ktime_on)
 		start = ktime_get_ns();
@@ -5431,6 +5577,25 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd)
 	}
 
 
+	/* check the necessary and sufficient condition to support VMID */
+	if (lpfc_is_vmid_enabled(phba) &&
+	    (ndlp->vmid_support ||
+	     phba->pport->vmid_priority_tagging ==
+	     LPFC_VMID_PRIO_TAG_ALL_TARGETS)) {
+		/* is the IO generated by a VM, get the associated virtual */
+		/* entity id */
+		uuid = lpfc_is_command_vm_io(cmnd);
+
+		if (uuid) {
+			err = lpfc_vmid_get_appid(vport, uuid, cmnd,
+				(union lpfc_vmid_io_tag *)
+					&lpfc_cmd->cur_iocbq.vmid_tag);
+			if (!err)
+				lpfc_cmd->cur_iocbq.iocb_flag |= LPFC_IO_VMID;
+		}
+	}
+
+	atomic_inc(&ndlp->cmd_pending);
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
 	if (unlikely(phba->hdwqstat_on & LPFC_CHECK_SCSI_IO))
 		this_cpu_inc(phba->sli4_hba.c_stat->xmt_io);
-- 
2.26.2



From muneendra.kumar at broadcom.com  Wed Jan  6 17:00:25 2021
From: muneendra.kumar at broadcom.com (Muneendra)
Date: Thu,  7 Jan 2021 03:30:25 +0530
Subject: [PATCH v7 11/16] lpfc: vmid: Implements CT commands for appid.
In-Reply-To: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
References: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
Message-ID: <1609970430-19084-12-git-send-email-muneendra.kumar@broadcom.com>

From: Gaurav Srivastava <gaurav.srivastava at broadcom.com>

The patch implements CT commands for registering and deregistering the
appid for the application. Also, a small change in decrementing the ndlp
ref counter has been added.

Reported-by: kernel test robot <lkp at intel.com>
Signed-off-by: Gaurav Srivastava  <gaurav.srivastava at broadcom.com>
Signed-off-by: James Smart <jsmart2021 at gmail.com>

---
v7:
No Change

v6:
Added Forward declarations and functions to static

v5:
No change

v4:
No change

v3:
No change

v2:
Ported the patch on top of 5.10/scsi-queue
Removed redundant code due to changes since last submit
---
 drivers/scsi/lpfc/lpfc_ct.c | 252 ++++++++++++++++++++++++++++++++++++
 1 file changed, 252 insertions(+)

diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index dd0b432f7ac5..fc1150e8adc6 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -75,6 +75,9 @@
 
 
 static char *lpfc_release_version = LPFC_DRIVER_VERSION;
+static void
+lpfc_cmpl_ct_cmd_vmid(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+		      struct lpfc_iocbq *rspiocb);
 
 static void
 lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
@@ -3744,3 +3747,252 @@ lpfc_decode_firmware_rev(struct lpfc_hba *phba, char *fwrevision, int flag)
 	}
 	return;
 }
+
+static void
+lpfc_cmpl_ct_cmd_vmid(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+		      struct lpfc_iocbq *rspiocb)
+{
+	struct lpfc_vport *vport = cmdiocb->vport;
+	struct lpfc_dmabuf *inp = cmdiocb->context1;
+	struct lpfc_dmabuf *outp = cmdiocb->context2;
+	struct lpfc_sli_ct_request *ctcmd = inp->virt;
+	struct lpfc_sli_ct_request *ctrsp = outp->virt;
+	u16 rsp = ctrsp->CommandResponse.bits.CmdRsp;
+	struct app_id_object *app;
+	u32 cmd, hash;
+	struct lpfc_vmid *vmp;
+	u8 *data = outp->virt;
+	int i;
+
+	cmd = be16_to_cpu(ctcmd->CommandResponse.bits.CmdRsp);
+	if (cmd == SLI_CTAS_DALLAPP_ID)
+		lpfc_ct_free_iocb(phba, cmdiocb);
+
+	if (lpfc_els_chk_latt(vport) || rspiocb->iocb.ulpStatus) {
+		if (cmd != SLI_CTAS_DALLAPP_ID)
+			return;
+	}
+	/* Check for a CT LS_RJT response */
+	if (rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
+		if (cmd != SLI_CTAS_DALLAPP_ID)
+			lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
+					 "3306 VMID FS_RJT Data: x%x  %x %x\n",
+				 cmd, ctrsp->ReasonCode, ctrsp->Explanation);
+		if ((cmd != SLI_CTAS_DALLAPP_ID) ||
+		    (ctrsp->ReasonCode != SLI_CT_UNABLE_TO_PERFORM_REQ) ||
+		    (ctrsp->Explanation != SLI_CT_APP_ID_NOT_AVAILABLE)) {
+			/* If DALLAPP_ID failed retry later */
+			if (cmd == SLI_CTAS_DALLAPP_ID)
+				vport->load_flag |= FC_DEREGISTER_ALL_APP_ID;
+			return;
+		}
+	}
+
+	switch (cmd) {
+	case SLI_CTAS_RAPP_IDENT:
+		app = (struct app_id_object *)(RAPP_IDENT_OFFSET + data);
+		lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
+				 "6712 RAPP_IDENT app id %d  port id %x id\n"
+				 "len %d\n", be32_to_cpu(app->app_id),
+				 be32_to_cpu(app->port_id),
+				 app->obj.entity_id_len);
+
+		if (app->obj.entity_id_len == 0 || app->port_id == 0)
+			return;
+
+		hash = lpfc_vmid_hash_fn(app->obj.entity_id,
+					 app->obj.entity_id_len);
+		vmp = lpfc_get_vmid_from_hastable(vport, hash,
+						  app->obj.entity_id);
+		if (vmp) {
+			vmp->un.app_id = be32_to_cpu(app->app_id);
+			vmp->flag |= LPFC_VMID_REGISTERED;
+			vmp->flag &= ~LPFC_VMID_REQ_REGISTER;
+			/* Set IN USE flag */
+			vport->vmid_flag |= LPFC_VMID_IN_USE;
+		} else {
+			lpfc_printf_vlog(vport, KERN_DEBUG,
+					 LOG_DISCOVERY, "6901 No entry found\n"
+					 "%s hash %d\n", app->obj.entity_id,
+					 hash);
+		}
+		break;
+	case SLI_CTAS_DAPP_IDENT:
+		app = (struct app_id_object *)(DAPP_IDENT_OFFSET + data);
+		lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
+				 "6713 DAPP_IDENT app id %d  port id %x",
+				 cpu_to_be32(app->app_id),
+				 cpu_to_be32(app->port_id));
+		break;
+	case SLI_CTAS_DALLAPP_ID:
+		lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
+				 "8856 Deregistered all app ids");
+		for (i = 0; i < phba->cfg_max_vmid; i++) {
+			vmp = &vport->vmid[i];
+			if (vmp->flag != LPFC_VMID_SLOT_FREE)
+				memset(vmp, 0, sizeof(struct lpfc_vmid));
+		}
+		for (i = 0; i < LPFC_VMID_HASH_SIZE; i++)
+			vport->hash_table[i] = NULL;
+		vport->load_flag |= FC_ALLOW_VMID;
+		break;
+	default:
+		lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
+				 "8857 Invalid command code");
+	}
+}
+
+/**
+ * lpfc_vmid_cmd - Build and send a FDMI cmd to the specified NPort
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @ndlp: ndlp to send FDMI cmd to (if NULL use FDMI_DID)
+ * cmdcode: FDMI command to send
+ * mask: Mask of HBA or PORT Attributes to send
+ *
+ * Builds and sends a FDMI command using the CT subsystem.
+ */
+int
+lpfc_vmid_cmd(struct lpfc_vport *vport,
+	      int cmdcode, struct lpfc_vmid *vmid)
+{
+	struct lpfc_hba *phba = vport->phba;
+	struct lpfc_dmabuf *mp, *bmp;
+	struct lpfc_sli_ct_request *ctreq;
+	struct ulp_bde64 *bpl;
+	u32 size;
+	u32 rsp_size;
+	u8 *data;
+	struct lpfc_vmid_rapp_ident_list *rap;
+	struct lpfc_vmid_dapp_ident_list *dap;
+	u8 retry = 0;
+	struct lpfc_nodelist *ndlp;
+
+	void (*cmpl)(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+		     struct lpfc_iocbq *rspiocb);
+
+	ndlp = lpfc_findnode_did(vport, FDMI_DID);
+	if (!ndlp || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)
+		return 0;
+
+	cmpl = lpfc_cmpl_ct_cmd_vmid;
+
+	/* fill in BDEs for command */
+	/* Allocate buffer for command payload */
+	mp = kmalloc(sizeof(*mp), GFP_KERNEL);
+	if (!mp)
+		goto vmid_free_mp_exit;
+
+	mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
+	if (!mp->virt)
+		goto vmid_free_mp_virt_exit;
+
+	/* Allocate buffer for Buffer ptr list */
+	bmp = kmalloc(sizeof(*bmp), GFP_KERNEL);
+	if (!bmp)
+		goto vmid_free_bmp_exit;
+
+	bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys);
+	if (!bmp->virt)
+		goto vmid_free_bmp_virt_exit;
+
+	INIT_LIST_HEAD(&mp->list);
+	INIT_LIST_HEAD(&bmp->list);
+
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+			 "0218 VMID Request Data: x%x x%x x%x",
+			 vport->fc_flag, vport->port_state, cmdcode);
+	ctreq = (struct lpfc_sli_ct_request *)mp->virt;
+	data = mp->virt;
+	/* First populate the CT_IU preamble */
+	memset(data, 0, LPFC_BPL_SIZE);
+	ctreq->RevisionId.bits.Revision = SLI_CT_REVISION;
+	ctreq->RevisionId.bits.InId = 0;
+
+	ctreq->FsType = SLI_CT_MANAGEMENT_SERVICE;
+	ctreq->FsSubType = SLI_CT_APP_SEV_Subtypes;
+
+	ctreq->CommandResponse.bits.CmdRsp = cpu_to_be16(cmdcode);
+	rsp_size = LPFC_BPL_SIZE;
+	size = 0;
+
+	switch (cmdcode) {
+	case SLI_CTAS_RAPP_IDENT:
+		lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
+				 "1329 RAPP_IDENT for %s", vmid->host_vmid);
+		ctreq->un.PortID = cpu_to_be32(vport->fc_myDID);
+		rap = (struct lpfc_vmid_rapp_ident_list *)
+			(DAPP_IDENT_OFFSET + data);
+		rap->no_of_objects = cpu_to_be32(1);
+		rap->obj[0].entity_id_len = vmid->vmid_len;
+		memcpy(rap->obj[0].entity_id, vmid->host_vmid, vmid->vmid_len);
+		size = RAPP_IDENT_OFFSET +
+			sizeof(struct lpfc_vmid_rapp_ident_list);
+		retry = 1;
+		break;
+
+	case SLI_CTAS_GALLAPPIA_ID:
+		ctreq->un.PortID = cpu_to_be32(vport->fc_myDID);
+		size = GALLAPPIA_ID_SIZE;
+		break;
+
+	case SLI_CTAS_DAPP_IDENT:
+		lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
+				 "1469 DAPP_IDENT for %s", vmid->host_vmid);
+		ctreq->un.PortID = cpu_to_be32(vport->fc_myDID);
+		dap = (struct lpfc_vmid_dapp_ident_list *)
+			(DAPP_IDENT_OFFSET + data);
+		dap->no_of_objects = cpu_to_be32(1);
+		dap->obj[0].entity_id_len = vmid->vmid_len;
+		memcpy(dap->obj[0].entity_id, vmid->host_vmid, vmid->vmid_len);
+		size = DAPP_IDENT_OFFSET +
+			sizeof(struct lpfc_vmid_dapp_ident_list);
+		vmid->flag &= ~LPFC_VMID_REGISTERED;
+		retry = 1;
+		break;
+
+	case SLI_CTAS_DALLAPP_ID:
+		ctreq->un.PortID = cpu_to_be32(vport->fc_myDID);
+		size = DALLAPP_ID_SIZE;
+		break;
+
+	default:
+		lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
+				 "7062 VMID cmdcode x%x not supported",
+				 cmdcode);
+		goto vmid_free_all_mem;
+	}
+
+	ctreq->CommandResponse.bits.Size = cpu_to_be16(rsp_size);
+
+	bpl = (struct ulp_bde64 *)bmp->virt;
+	bpl->addrHigh = putPaddrHigh(mp->phys);
+	bpl->addrLow = putPaddrLow(mp->phys);
+	bpl->tus.f.bdeFlags = 0;
+	bpl->tus.f.bdeSize = size;
+
+	/* The lpfc_ct_cmd/lpfc_get_req shall increment ndlp reference count
+	 * to hold ndlp reference for the corresponding callback function.
+	 */
+	if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size, retry))
+		return 0;
+
+	/* Decrement ndlp reference count to release ndlp reference held
+	 * for the failed command's callback function.
+	 */
+	lpfc_nlp_put(ndlp);
+
+ vmid_free_all_mem:
+	lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
+ vmid_free_bmp_virt_exit:
+	kfree(bmp);
+ vmid_free_bmp_exit:
+	lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ vmid_free_mp_virt_exit:
+	kfree(mp);
+ vmid_free_mp_exit:
+
+	/* Issue FDMI request failed */
+	lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
+			 "0244 Issue FDMI request failed Data: x%x", cmdcode);
+	return FAILURE;
+}
-- 
2.26.2



From israelr at nvidia.com  Thu Jan  7 10:34:13 2021
From: israelr at nvidia.com (Israel Rukshin)
Date: Thu,  7 Jan 2021 17:34:13 +0200
Subject: [PATCH 1/2] nvmet: Use nvmet_is_port_enabled helper for pi_enable
Message-ID: <1610033654-25186-1-git-send-email-israelr@nvidia.com>

Remove code duplication.

Signed-off-by: Israel Rukshin <israelr at nvidia.com>
Reviewed-by: Max Gurtovoy <mgurtovoy at nvidia.com>
---
 drivers/nvme/target/configfs.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c
index c61ffd767062..b2021bf6cee5 100644
--- a/drivers/nvme/target/configfs.c
+++ b/drivers/nvme/target/configfs.c
@@ -266,10 +266,8 @@ static ssize_t nvmet_param_pi_enable_store(struct config_item *item,
 	if (strtobool(page, &val))
 		return -EINVAL;
 
-	if (port->enabled) {
-		pr_err("Disable port before setting pi_enable value.\n");
+	if (nvmet_is_port_enabled(port, __func__))
 		return -EACCES;
-	}
 
 	port->pi_enable = val;
 	return count;
-- 
2.18.2



From israelr at nvidia.com  Thu Jan  7 10:34:14 2021
From: israelr at nvidia.com (Israel Rukshin)
Date: Thu,  7 Jan 2021 17:34:14 +0200
Subject: [PATCH 2/2] nvmet: Fix nvmet_is_port_enabled indentation
In-Reply-To: <1610033654-25186-1-git-send-email-israelr@nvidia.com>
References: <1610033654-25186-1-git-send-email-israelr@nvidia.com>
Message-ID: <1610033654-25186-2-git-send-email-israelr@nvidia.com>

Remove extra tab.

Signed-off-by: Israel Rukshin <israelr at nvidia.com>
Reviewed-by: Max Gurtovoy <mgurtovoy at nvidia.com>
---
 drivers/nvme/target/configfs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c
index b2021bf6cee5..635a7cb45d0b 100644
--- a/drivers/nvme/target/configfs.c
+++ b/drivers/nvme/target/configfs.c
@@ -45,7 +45,7 @@ static bool nvmet_is_port_enabled(struct nvmet_port *p, const char *caller)
 {
 	if (p->enabled)
 		pr_err("Disable port '%u' before changing attribute in %s\n",
-				le16_to_cpu(p->disc_addr.portid), caller);
+		       le16_to_cpu(p->disc_addr.portid), caller);
 	return p->enabled;
 }
 
-- 
2.18.2



From hch at infradead.org  Thu Jan  7 12:42:51 2021
From: hch at infradead.org (Christoph Hellwig)
Date: Thu, 7 Jan 2021 18:42:51 +0100
Subject: [GIT PULL] nvme fixes for 5.11
Message-ID: <X/dIG7478C6ahGvo@infradead.org>

The following changes since commit aebf5db917055b38f4945ed6d621d9f07a44ff30:

  block: fix use-after-free in disk_part_iter_next (2021-01-05 11:35:17 -0700)

are available in the Git repository at:

  git://git.infradead.org/nvme.git tags/nvme-5.11-2021-01-07

for you to fetch changes up to 2b59787a223b79228fed9ade1bf6936194ddb8cd:

  nvme: remove the unused status argument from nvme_trace_bio_complete (2021-01-06 10:30:37 +0100)

----------------------------------------------------------------
nvme updates for 5.11:

 - fix a race in the nvme-tcp send code (Sagi Grimberg)
 - fix a list corruption in an nvme-rdma error path (Israel Rukshin)
 - avoid a possible double fetch in nvme-pci (Lalithambika Krishnakumar)
 - add the susystem NQN quirk for a Samsung driver (Gopal Tiwari)
 - fix two compiler warnings in nvme-fcloop (James Smart)
 - don't call sleeping functions from irq context in nvme-fc (James Smart)
 - remove an unused argument (Max Gurtovoy)
 - remove unused exports (Minwoo Im)

----------------------------------------------------------------
Gopal Tiwari (1):
      nvme-pci: mark Samsung PM1725a as IGNORE_DEV_SUBNQN

Israel Rukshin (1):
      nvmet-rdma: Fix list_del corruption on queue establishment failure

James Smart (2):
      nvme-fc: avoid calling _nvme_fc_abort_outstanding_ios from interrupt context
      nvme-fcloop: Fix sscanf type and list_first_entry_or_null warnings

Lalithambika Krishnakumar (1):
      nvme: avoid possible double fetch in handling CQE

Max Gurtovoy (1):
      nvme: remove the unused status argument from nvme_trace_bio_complete

Minwoo Im (1):
      nvme: unexport functions with no external caller

Sagi Grimberg (1):
      nvme-tcp: Fix possible race of io_work and direct send

 drivers/nvme/host/core.c     |  8 +++-----
 drivers/nvme/host/fc.c       | 15 ++++++++++++++-
 drivers/nvme/host/nvme.h     |  9 ++-------
 drivers/nvme/host/pci.c      | 10 ++++++----
 drivers/nvme/host/tcp.c      | 12 +++++++++++-
 drivers/nvme/target/fcloop.c |  7 ++++---
 drivers/nvme/target/rdma.c   | 10 ++++++++++
 7 files changed, 50 insertions(+), 21 deletions(-)


From axboe at kernel.dk  Thu Jan  7 12:58:35 2021
From: axboe at kernel.dk (Jens Axboe)
Date: Thu, 7 Jan 2021 10:58:35 -0700
Subject: [GIT PULL] nvme fixes for 5.11
In-Reply-To: <X/dIG7478C6ahGvo@infradead.org>
References: <X/dIG7478C6ahGvo@infradead.org>
Message-ID: <b91e3bd1-0f99-0aee-3e5a-1a8cd466f367@kernel.dk>

On 1/7/21 10:42 AM, Christoph Hellwig wrote:
>   git://git.infradead.org/nvme.git tags/nvme-5.11-2021-01-07

Pulled, thanks.

-- 
Jens Axboe



From gerlitz.or at gmail.com  Thu Jan  7 14:05:32 2021
From: gerlitz.or at gmail.com (Or Gerlitz)
Date: Thu, 7 Jan 2021 21:05:32 +0200
Subject: [PATCH] nvme-tcp: Fix possible race of io_work and direct send
In-Reply-To: <20201221080339.945164-1-sagi@grimberg.me>
References: <20201221080339.945164-1-sagi@grimberg.me>
Message-ID: <CAJ3xEMj8Y_=Y=orV59GR9=L4M3r4+mZzMW6w2cv2K9d5eKXZDA@mail.gmail.com>

On Mon, Dec 21, 2020 at 10:06 AM Sagi Grimberg <sagi at grimberg.me> wrote:
> We may send a request (with or without its data) from two paths:
> 1. From our I/O context nvme_tcp_io_work which is triggered from:
> - queue_rq
> - r2t reception
> - socket data_ready and write_space callbacks

> 2. Directly from queue_rq if the send_list is empty (because
> we want to save the context switch associated with scheduling
> our io_work).

> Fixes: db5ad6b7f8cd ("nvme-tcp: try to send request in queue_rq context")
> Reported-by: Potnuri Bharat Teja <bharat at chelsio.com>
> Reported-by: Samuel Jones <sjones at kalrayinc.com>

> --- a/drivers/nvme/host/tcp.c
> +++ b/drivers/nvme/host/tcp.c

> @@ -279,7 +289,7 @@ static inline void nvme_tcp_queue_request(struct nvme_tcp_request *req,
>         if (queue->io_cpu == smp_processor_id() &&
>             sync && empty && mutex_trylock(&queue->send_mutex)) {

but we can't rely on the processor id if we are on preemptible state..

  373.940336] BUG: using smp_processor_id() in preemptible [00000000]
code: kworker/u8:4/457
[  373.942037] caller is nvme_tcp_submit_async_event+0x4da/0x690 [nvme_tcp]
[  373.942144] CPU: 0 PID: 457 Comm: kworker/u8:4 Not tainted 5.11.0-rc1+ #116
[  373.942171] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),
BIOS rel-1.12.1-0-ga5cab58e9a3f-prebuilt.qemu.org 04/01/2014
[  373.942196] Workqueue: nvme-wq nvme_async_event_work [nvme_core]
[  373.942259] Call Trace:
[  373.942286]  dump_stack+0xd0/0x119
[  373.942346]  check_preemption_disabled+0xec/0xf0
[  373.942397]  nvme_tcp_submit_async_event+0x4da/0x690 [nvme_tcp]
[  373.942449]  nvme_async_event_work+0x11d/0x1f0 [nvme_core]
[  373.942496]  ? nvme_ctrl_loss_tmo_show+0x140/0x140 [nvme_core]
[  373.942576]  process_one_work+0x9f3/0x1630
[  373.942649]  ? pwq_dec_nr_in_flight+0x330/0x330
[  373.942765]  worker_thread+0x9e/0xf60
[  373.942849]  ? process_one_work+0x1630/0x1630
[  373.942889]  kthread+0x362/0x480
[  373.942918]  ? kthread_create_on_node+0x100/0x100

       /*
+        * if we're the first on the send_list and we can try to send
+        * directly, otherwise queue io_work. Also, only do that if we
+        * are on the same cpu, so we don't introduce contention.
+        */
+       if (queue->io_cpu == smp_processor_id() &&
+           sync && empty && mutex_trylock(&queue->send_mutex)) {
+               nvme_tcp_try_send(queue);
+               mutex_unlock(&queue->send_mutex);
+       } else {
+               queue_work_on(queue->io_cpu, nvme_tcp_wq, &queue->io_work);
+       }

so before this patch that check was not needed? I was not sure re all
the involved contexts and how to fix that.. so just sending the report


From jgg at nvidia.com  Thu Jan  7 14:38:38 2021
From: jgg at nvidia.com (Jason Gunthorpe)
Date: Thu, 7 Jan 2021 15:38:38 -0400
Subject: [PATCH v3] RDMA/siw: Fix handling of zero-sized Read and Receive
 Queues.
In-Reply-To: <20201216110000.611-1-bmt@zurich.ibm.com>
References: <20201216110000.611-1-bmt@zurich.ibm.com>
Message-ID: <20210107193838.GA921419@nvidia.com>

On Wed, Dec 16, 2020 at 12:00:00PM +0100, Bernard Metzler wrote:
> @@ -933,6 +937,7 @@ int siw_activate_tx(struct siw_qp *qp)
>  
>  		goto out;
>  	}
> +no_irq:
>  	sqe = sq_get_next(qp);
>  	if (sqe) {

Can you please arrange this without the spaghetti goto's? goto is ok
for error unwind at the tail of the function, but should not be used
willy nilly. Move some of this into functions, use normal if
statements, etc.

Jason


From BMT at zurich.ibm.com  Fri Jan  8 05:51:23 2021
From: BMT at zurich.ibm.com (Bernard Metzler)
Date: Fri, 8 Jan 2021 10:51:23 +0000
Subject: [PATCH v3] RDMA/siw: Fix handling of zero-sized Read and Receive
 Queues.
In-Reply-To: <20210107193838.GA921419@nvidia.com>
References: <20210107193838.GA921419@nvidia.com>,
 <20201216110000.611-1-bmt@zurich.ibm.com>
Message-ID: <OF12D28384.4EE6A087-ON00258657.003BA30F-00258657.003BA319@notes.na.collabserv.com>

-----"Jason Gunthorpe" <jgg at nvidia.com> wrote: -----

>To: "Bernard Metzler" <bmt at zurich.ibm.com>
>From: "Jason Gunthorpe" <jgg at nvidia.com>
>Date: 01/07/2021 08:40PM
>Cc: <linux-rdma at vger.kernel.org>, <linux-nvme at lists.infradead.org>,
><leon at kernel.org>, "Kamal Heib" <kamalheib1 at gmail.com>, "Yi Zhang"
><yi.zhang at redhat.com>, "kernel test robot" <lkp at intel.com>
>Subject: [EXTERNAL] Re: [PATCH v3] RDMA/siw: Fix handling of
>zero-sized Read and Receive Queues.
>
>On Wed, Dec 16, 2020 at 12:00:00PM +0100, Bernard Metzler wrote:
>> @@ -933,6 +937,7 @@ int siw_activate_tx(struct siw_qp *qp)
>>  
>>  		goto out;
>>  	}
>> +no_irq:
>>  	sqe = sq_get_next(qp);
>>  	if (sqe) {
>
>Can you please arrange this without the spaghetti goto's? goto is ok
>for error unwind at the tail of the function, but should not be used
>willy nilly. Move some of this into functions, use normal if
>statements, etc.
>
Okay. I tried to minimize changes but I now think
you are right - it's time to cleanup before it
gets too burlesque.

Will send a v4.

Thanks
Bernard.



From yi.zhang at redhat.com  Fri Jan  8 06:23:03 2021
From: yi.zhang at redhat.com (Yi Zhang)
Date: Fri, 8 Jan 2021 19:23:03 +0800
Subject: [PATCH] nvme-tcp: Fix possible race of io_work and direct send
In-Reply-To: <CAJ3xEMj8Y_=Y=orV59GR9=L4M3r4+mZzMW6w2cv2K9d5eKXZDA@mail.gmail.com>
References: <20201221080339.945164-1-sagi@grimberg.me>
 <CAJ3xEMj8Y_=Y=orV59GR9=L4M3r4+mZzMW6w2cv2K9d5eKXZDA@mail.gmail.com>
Message-ID: <041e694c-b3bf-a79a-3397-93ab96275f3a@redhat.com>



On 1/8/21 3:05 AM, Or Gerlitz wrote:
> On Mon, Dec 21, 2020 at 10:06 AM Sagi Grimberg <sagi at grimberg.me> wrote:
>> We may send a request (with or without its data) from two paths:
>> 1. From our I/O context nvme_tcp_io_work which is triggered from:
>> - queue_rq
>> - r2t reception
>> - socket data_ready and write_space callbacks
>> 2. Directly from queue_rq if the send_list is empty (because
>> we want to save the context switch associated with scheduling
>> our io_work).
>> Fixes: db5ad6b7f8cd ("nvme-tcp: try to send request in queue_rq context")
>> Reported-by: Potnuri Bharat Teja <bharat at chelsio.com>
>> Reported-by: Samuel Jones <sjones at kalrayinc.com>
>> --- a/drivers/nvme/host/tcp.c
>> +++ b/drivers/nvme/host/tcp.c
>> @@ -279,7 +289,7 @@ static inline void nvme_tcp_queue_request(struct nvme_tcp_request *req,
>>          if (queue->io_cpu == smp_processor_id() &&
>>              sync && empty && mutex_trylock(&queue->send_mutex)) {
> but we can't rely on the processor id if we are on preemptible state..
>
>    373.940336] BUG: using smp_processor_id() in preemptible [00000000]
> code: kworker/u8:4/457
> [  373.942037] caller is nvme_tcp_submit_async_event+0x4da/0x690 [nvme_tcp]
> [  373.942144] CPU: 0 PID: 457 Comm: kworker/u8:4 Not tainted 5.11.0-rc1+ #116
> [  373.942171] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),
> BIOS rel-1.12.1-0-ga5cab58e9a3f-prebuilt.qemu.org 04/01/2014
> [  373.942196] Workqueue: nvme-wq nvme_async_event_work [nvme_core]
> [  373.942259] Call Trace:
> [  373.942286]  dump_stack+0xd0/0x119
> [  373.942346]  check_preemption_disabled+0xec/0xf0
> [  373.942397]  nvme_tcp_submit_async_event+0x4da/0x690 [nvme_tcp]
> [  373.942449]  nvme_async_event_work+0x11d/0x1f0 [nvme_core]
> [  373.942496]  ? nvme_ctrl_loss_tmo_show+0x140/0x140 [nvme_core]
> [  373.942576]  process_one_work+0x9f3/0x1630
> [  373.942649]  ? pwq_dec_nr_in_flight+0x330/0x330
> [  373.942765]  worker_thread+0x9e/0xf60
> [  373.942849]  ? process_one_work+0x1630/0x1630
> [  373.942889]  kthread+0x362/0x480
> [  373.942918]  ? kthread_create_on_node+0x100/0x100
>
>         /*
> +        * if we're the first on the send_list and we can try to send
> +        * directly, otherwise queue io_work. Also, only do that if we
> +        * are on the same cpu, so we don't introduce contention.
> +        */
> +       if (queue->io_cpu == smp_processor_id() &&
> +           sync && empty && mutex_trylock(&queue->send_mutex)) {
> +               nvme_tcp_try_send(queue);
> +               mutex_unlock(&queue->send_mutex);
> +       } else {
> +               queue_work_on(queue->io_cpu, nvme_tcp_wq, &queue->io_work);
> +       }
>
> so before this patch that check was not needed? I was not sure re all
> the involved contexts and how to fix that.. so just sending the report
Yeah, I met similar issue after enable PREEMPT.

[? 135.285366] run blktests nvme/003 at 2021-01-08 06:13:04
[? 135.358457] loop: module loaded
[? 135.368607] nvmet: adding nsid 1 to subsystem blktests-subsystem-1
[? 135.369568] nvmet_tcp: enabling port 0 (127.0.0.1:4420)
[? 135.374261] nvmet: creating controller 1 for subsystem 
nqn.2014-08.org.nvmexpress.discovery for NQN 
nqn.2014-08.org.nvmexpress:uuid:0d2e879c-9efb-4026-a82e-450e4283175e.
[? 135.374381] nvme nvme0: new ctrl: NQN 
"nqn.2014-08.org.nvmexpress.discovery", addr 127.0.0.1:4420
[? 135.374382] BUG: using smp_processor_id() in preemptible [00000000] 
code: kworker/u64:18/187
[? 135.374387] caller is nvme_tcp_submit_async_event+0x111/0x140 [nvme_tcp]
[? 135.389518] CPU: 31 PID: 187 Comm: kworker/u64:18 Tainted: G S??????? 
I?????? 5.11.0-rc2.v1 #2
[? 135.398121] Hardware name: Dell Inc. PowerEdge R640/06NR82, BIOS 
2.10.0 11/12/2020
[? 135.405688] Workqueue: nvme-wq nvme_async_event_work [nvme_core]
[? 135.411704] Call Trace:
[? 135.414157]? dump_stack+0x57/0x6a
[? 135.417475]? check_preemption_disabled+0xb6/0xd0
[? 135.422094]? nvme_tcp_submit_async_event+0x111/0x140 [nvme_tcp]
[? 135.428014]? nvme_async_event_work+0x5d/0xc0 [nvme_core]
[? 135.433324]? process_one_work+0x1b6/0x3b0
[? 135.437337]? worker_thread+0x30/0x370
[? 135.441002]? ? process_one_work+0x3b0/0x3b0
[? 135.445190]? kthread+0x13d/0x160
[? 135.448423]? ? kthread_park+0x80/0x80
[? 135.452089]? ret_from_fork+0x1f/0x30
[? 145.394927] nvme nvme0: Removing ctrl: NQN 
"nqn.2014-08.org.nvmexpress.discovery"


> _______________________________________________
> Linux-nvme mailing list
> Linux-nvme at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-nvme
>



From bmt at zurich.ibm.com  Fri Jan  8 07:58:45 2021
From: bmt at zurich.ibm.com (Bernard Metzler)
Date: Fri,  8 Jan 2021 13:58:45 +0100
Subject: [PATCH v4] RDMA/siw: Fix handling of zero-sized Read and Receive
 Queues.
Message-ID: <20210108125845.1803-1-bmt@zurich.ibm.com>

During connection setup, the application may choose to zero-size
inbound and outbound READ queues, as well as the Receive queue.
This patch fixes handling of zero-sized queues, but not prevents
it.

Kamal Heib says in an initial error report:
When running the blktests over siw the following shift-out-of-bounds is
reported, this is happening because the passed IRD or ORD from the ulp
could be zero which will lead to unexpected behavior when calling
roundup_pow_of_two(), fix that by blocking zero values of ORD or IRD.

UBSAN: shift-out-of-bounds in ./include/linux/log2.h:57:13
shift exponent 64 is too large for 64-bit type 'long unsigned int'
CPU: 20 PID: 3957 Comm: kworker/u64:13 Tainted: G S     5.10.0-rc6 #2
Hardware name: Dell Inc. PowerEdge R630/02C2CP, BIOS 2.1.5 04/11/2016
Workqueue: iw_cm_wq cm_work_handler [iw_cm]
Call Trace:
 dump_stack+0x99/0xcb
 ubsan_epilogue+0x5/0x40
 __ubsan_handle_shift_out_of_bounds.cold.11+0xb4/0xf3
 ? down_write+0x183/0x3d0
 siw_qp_modify.cold.8+0x2d/0x32 [siw]
 ? __local_bh_enable_ip+0xa5/0xf0
 siw_accept+0x906/0x1b60 [siw]
 ? xa_load+0x147/0x1f0
 ? siw_connect+0x17a0/0x17a0 [siw]
 ? lock_downgrade+0x700/0x700
 ? siw_get_base_qp+0x1c2/0x340 [siw]
 ? _raw_spin_unlock_irqrestore+0x39/0x40
 iw_cm_accept+0x1f4/0x430 [iw_cm]
 rdma_accept+0x3fa/0xb10 [rdma_cm]
 ? check_flush_dependency+0x410/0x410
 ? cma_rep_recv+0x570/0x570 [rdma_cm]
 nvmet_rdma_queue_connect+0x1a62/0x2680 [nvmet_rdma]
 ? nvmet_rdma_alloc_cmds+0xce0/0xce0 [nvmet_rdma]
 ? lock_release+0x56e/0xcc0
 ? lock_downgrade+0x700/0x700
 ? lock_downgrade+0x700/0x700
 ? __xa_alloc_cyclic+0xef/0x350
 ? __xa_alloc+0x2d0/0x2d0
 ? rdma_restrack_add+0xbe/0x2c0 [ib_core]
 ? __ww_mutex_die+0x190/0x190
 cma_cm_event_handler+0xf2/0x500 [rdma_cm]
 iw_conn_req_handler+0x910/0xcb0 [rdma_cm]
 ? _raw_spin_unlock_irqrestore+0x39/0x40
 ? trace_hardirqs_on+0x1c/0x150
 ? cma_ib_handler+0x8a0/0x8a0 [rdma_cm]
 ? __kasan_kmalloc.constprop.7+0xc1/0xd0
 cm_work_handler+0x121c/0x17a0 [iw_cm]
 ? iw_cm_reject+0x190/0x190 [iw_cm]
 ? trace_hardirqs_on+0x1c/0x150
 process_one_work+0x8fb/0x16c0
 ? pwq_dec_nr_in_flight+0x320/0x320
 worker_thread+0x87/0xb40
 ? __kthread_parkme+0xd1/0x1a0
 ? process_one_work+0x16c0/0x16c0
 kthread+0x35f/0x430
 ? kthread_mod_delayed_work+0x180/0x180
 ret_from_fork+0x22/0x30

Fixes: a531975279f3 ("rdma/siw: main include file")
Fixes: f29dd55b0236 ("rdma/siw: queue pair methods")
Fixes: 8b6a361b8c48 ("rdma/siw: receive path")
Fixes: b9be6f18cf9e ("rdma/siw: transmit path")
Fixes: 303ae1cdfdf7 ("rdma/siw: application interface")
Reported-by: Kamal Heib <kamalheib1 at gmail.com>
Reported-by: Yi Zhang <yi.zhang at redhat.com>
Reported-by: kernel test robot <lkp at intel.com>
Signed-off-by: Bernard Metzler <bmt at zurich.ibm.com>
---
v2 changes:
- Fix uninitialized variable introduced in siw_qp_rx.c, as
  Reported-by: kernel test robot <lkp at intel.com>
- Add initial error report as
  Reported-by: Kamal Heib <kamalheib1 at gmail.com>

v3 changes:
- correct patch changelog location
- remove prints for failed queue malloc's as pointed out by
  Leon Romanovsky

v4 changes:
- unwind siw_activate_tx function avoiding confusing
  goto's as requested by Jason Gunthorp

 drivers/infiniband/sw/siw/siw.h       |   2 +-
 drivers/infiniband/sw/siw/siw_qp.c    | 271 ++++++++++++++------------
 drivers/infiniband/sw/siw/siw_qp_rx.c |  26 ++-
 drivers/infiniband/sw/siw/siw_qp_tx.c |   4 +-
 drivers/infiniband/sw/siw/siw_verbs.c |  20 +-
 5 files changed, 177 insertions(+), 146 deletions(-)

diff --git a/drivers/infiniband/sw/siw/siw.h b/drivers/infiniband/sw/siw/siw.h
index e9753831ac3f..6f17392f975a 100644
--- a/drivers/infiniband/sw/siw/siw.h
+++ b/drivers/infiniband/sw/siw/siw.h
@@ -654,7 +654,7 @@ static inline struct siw_sqe *orq_get_free(struct siw_qp *qp)
 {
 	struct siw_sqe *orq_e = orq_get_tail(qp);
 
-	if (orq_e && READ_ONCE(orq_e->flags) == 0)
+	if (READ_ONCE(orq_e->flags) == 0)
 		return orq_e;
 
 	return NULL;
diff --git a/drivers/infiniband/sw/siw/siw_qp.c b/drivers/infiniband/sw/siw/siw_qp.c
index 875d36d4b1c6..ddb2e66f9f13 100644
--- a/drivers/infiniband/sw/siw/siw_qp.c
+++ b/drivers/infiniband/sw/siw/siw_qp.c
@@ -199,26 +199,26 @@ void siw_qp_llp_write_space(struct sock *sk)
 
 static int siw_qp_readq_init(struct siw_qp *qp, int irq_size, int orq_size)
 {
-	irq_size = roundup_pow_of_two(irq_size);
-	orq_size = roundup_pow_of_two(orq_size);
-
-	qp->attrs.irq_size = irq_size;
-	qp->attrs.orq_size = orq_size;
-
-	qp->irq = vzalloc(irq_size * sizeof(struct siw_sqe));
-	if (!qp->irq) {
-		siw_dbg_qp(qp, "irq malloc for %d failed\n", irq_size);
-		qp->attrs.irq_size = 0;
-		return -ENOMEM;
+	if (irq_size) {
+		irq_size = roundup_pow_of_two(irq_size);
+		qp->irq = vzalloc(irq_size * sizeof(struct siw_sqe));
+		if (!qp->irq) {
+			qp->attrs.irq_size = 0;
+			return -ENOMEM;
+		}
 	}
-	qp->orq = vzalloc(orq_size * sizeof(struct siw_sqe));
-	if (!qp->orq) {
-		siw_dbg_qp(qp, "orq malloc for %d failed\n", orq_size);
-		qp->attrs.orq_size = 0;
-		qp->attrs.irq_size = 0;
-		vfree(qp->irq);
-		return -ENOMEM;
+	if (orq_size) {
+		orq_size = roundup_pow_of_two(orq_size);
+		qp->orq = vzalloc(orq_size * sizeof(struct siw_sqe));
+		if (!qp->orq) {
+			qp->attrs.orq_size = 0;
+			qp->attrs.irq_size = 0;
+			vfree(qp->irq);
+			return -ENOMEM;
+		}
 	}
+	qp->attrs.irq_size = irq_size;
+	qp->attrs.orq_size = orq_size;
 	siw_dbg_qp(qp, "ORD %d, IRD %d\n", orq_size, irq_size);
 	return 0;
 }
@@ -288,13 +288,14 @@ int siw_qp_mpa_rts(struct siw_qp *qp, enum mpa_v2_ctrl ctrl)
 	if (ctrl & MPA_V2_RDMA_WRITE_RTR)
 		wqe->sqe.opcode = SIW_OP_WRITE;
 	else if (ctrl & MPA_V2_RDMA_READ_RTR) {
-		struct siw_sqe *rreq;
+		struct siw_sqe *rreq = NULL;
 
 		wqe->sqe.opcode = SIW_OP_READ;
 
 		spin_lock(&qp->orq_lock);
 
-		rreq = orq_get_free(qp);
+		if (qp->attrs.orq_size)
+			rreq = orq_get_free(qp);
 		if (rreq) {
 			siw_read_to_orq(rreq, &wqe->sqe);
 			qp->orq_put++;
@@ -877,135 +878,88 @@ void siw_read_to_orq(struct siw_sqe *rreq, struct siw_sqe *sqe)
 	rreq->num_sge = 1;
 }
 
-/*
- * Must be called with SQ locked.
- * To avoid complete SQ starvation by constant inbound READ requests,
- * the active IRQ will not be served after qp->irq_burst, if the
- * SQ has pending work.
- */
-int siw_activate_tx(struct siw_qp *qp)
+static int siw_activate_tx_from_sq(struct siw_qp *qp)
 {
-	struct siw_sqe *irqe, *sqe;
+	struct siw_sqe *sqe;
 	struct siw_wqe *wqe = tx_wqe(qp);
 	int rv = 1;
 
-	irqe = &qp->irq[qp->irq_get % qp->attrs.irq_size];
-
-	if (irqe->flags & SIW_WQE_VALID) {
-		sqe = sq_get_next(qp);
-
-		/*
-		 * Avoid local WQE processing starvation in case
-		 * of constant inbound READ request stream
-		 */
-		if (sqe && ++qp->irq_burst >= SIW_IRQ_MAXBURST_SQ_ACTIVE) {
-			qp->irq_burst = 0;
-			goto skip_irq;
-		}
-		memset(wqe->mem, 0, sizeof(*wqe->mem) * SIW_MAX_SGE);
-		wqe->wr_status = SIW_WR_QUEUED;
-
-		/* start READ RESPONSE */
-		wqe->sqe.opcode = SIW_OP_READ_RESPONSE;
-		wqe->sqe.flags = 0;
-		if (irqe->num_sge) {
-			wqe->sqe.num_sge = 1;
-			wqe->sqe.sge[0].length = irqe->sge[0].length;
-			wqe->sqe.sge[0].laddr = irqe->sge[0].laddr;
-			wqe->sqe.sge[0].lkey = irqe->sge[0].lkey;
-		} else {
-			wqe->sqe.num_sge = 0;
-		}
-
-		/* Retain original RREQ's message sequence number for
-		 * potential error reporting cases.
-		 */
-		wqe->sqe.sge[1].length = irqe->sge[1].length;
-
-		wqe->sqe.rkey = irqe->rkey;
-		wqe->sqe.raddr = irqe->raddr;
+	sqe = sq_get_next(qp);
+	if (!sqe)
+		return 0;
 
-		wqe->processed = 0;
-		qp->irq_get++;
+	memset(wqe->mem, 0, sizeof(*wqe->mem) * SIW_MAX_SGE);
+	wqe->wr_status = SIW_WR_QUEUED;
 
-		/* mark current IRQ entry free */
-		smp_store_mb(irqe->flags, 0);
+	/* First copy SQE to kernel private memory */
+	memcpy(&wqe->sqe, sqe, sizeof(*sqe));
 
+	if (wqe->sqe.opcode >= SIW_NUM_OPCODES) {
+		rv = -EINVAL;
 		goto out;
 	}
-	sqe = sq_get_next(qp);
-	if (sqe) {
-skip_irq:
-		memset(wqe->mem, 0, sizeof(*wqe->mem) * SIW_MAX_SGE);
-		wqe->wr_status = SIW_WR_QUEUED;
-
-		/* First copy SQE to kernel private memory */
-		memcpy(&wqe->sqe, sqe, sizeof(*sqe));
-
-		if (wqe->sqe.opcode >= SIW_NUM_OPCODES) {
+	if (wqe->sqe.flags & SIW_WQE_INLINE) {
+		if (wqe->sqe.opcode != SIW_OP_SEND &&
+		    wqe->sqe.opcode != SIW_OP_WRITE) {
 			rv = -EINVAL;
 			goto out;
 		}
-		if (wqe->sqe.flags & SIW_WQE_INLINE) {
-			if (wqe->sqe.opcode != SIW_OP_SEND &&
-			    wqe->sqe.opcode != SIW_OP_WRITE) {
-				rv = -EINVAL;
-				goto out;
-			}
-			if (wqe->sqe.sge[0].length > SIW_MAX_INLINE) {
-				rv = -EINVAL;
-				goto out;
-			}
-			wqe->sqe.sge[0].laddr = (uintptr_t)&wqe->sqe.sge[1];
-			wqe->sqe.sge[0].lkey = 0;
-			wqe->sqe.num_sge = 1;
+		if (wqe->sqe.sge[0].length > SIW_MAX_INLINE) {
+			rv = -EINVAL;
+			goto out;
 		}
-		if (wqe->sqe.flags & SIW_WQE_READ_FENCE) {
-			/* A READ cannot be fenced */
-			if (unlikely(wqe->sqe.opcode == SIW_OP_READ ||
-				     wqe->sqe.opcode ==
-					     SIW_OP_READ_LOCAL_INV)) {
-				siw_dbg_qp(qp, "cannot fence read\n");
-				rv = -EINVAL;
-				goto out;
-			}
-			spin_lock(&qp->orq_lock);
+		wqe->sqe.sge[0].laddr = (uintptr_t)&wqe->sqe.sge[1];
+		wqe->sqe.sge[0].lkey = 0;
+		wqe->sqe.num_sge = 1;
+	}
+	if (wqe->sqe.flags & SIW_WQE_READ_FENCE) {
+		/* A READ cannot be fenced */
+		if (unlikely(wqe->sqe.opcode == SIW_OP_READ ||
+			     wqe->sqe.opcode ==
+				     SIW_OP_READ_LOCAL_INV)) {
+			siw_dbg_qp(qp, "cannot fence read\n");
+			rv = -EINVAL;
+			goto out;
+		}
+		spin_lock(&qp->orq_lock);
 
-			if (!siw_orq_empty(qp)) {
-				qp->tx_ctx.orq_fence = 1;
-				rv = 0;
-			}
-			spin_unlock(&qp->orq_lock);
+		if (qp->attrs.orq_size && !siw_orq_empty(qp)) {
+			qp->tx_ctx.orq_fence = 1;
+			rv = 0;
+		}
+		spin_unlock(&qp->orq_lock);
 
-		} else if (wqe->sqe.opcode == SIW_OP_READ ||
-			   wqe->sqe.opcode == SIW_OP_READ_LOCAL_INV) {
-			struct siw_sqe *rreq;
+	} else if (wqe->sqe.opcode == SIW_OP_READ ||
+		   wqe->sqe.opcode == SIW_OP_READ_LOCAL_INV) {
+		struct siw_sqe *rreq;
 
-			wqe->sqe.num_sge = 1;
+		if (unlikely(!qp->attrs.orq_size)) {
+			/* We negotiated not to send READ req's */
+			rv = -EINVAL;
+			goto out;
+		}
+		wqe->sqe.num_sge = 1;
 
-			spin_lock(&qp->orq_lock);
+		spin_lock(&qp->orq_lock);
 
-			rreq = orq_get_free(qp);
-			if (rreq) {
-				/*
-				 * Make an immediate copy in ORQ to be ready
-				 * to process loopback READ reply
-				 */
-				siw_read_to_orq(rreq, &wqe->sqe);
-				qp->orq_put++;
-			} else {
-				qp->tx_ctx.orq_fence = 1;
-				rv = 0;
-			}
-			spin_unlock(&qp->orq_lock);
+		rreq = orq_get_free(qp);
+		if (rreq) {
+			/*
+			 * Make an immediate copy in ORQ to be ready
+			 * to process loopback READ reply
+			 */
+			siw_read_to_orq(rreq, &wqe->sqe);
+			qp->orq_put++;
+		} else {
+			qp->tx_ctx.orq_fence = 1;
+			rv = 0;
 		}
-
-		/* Clear SQE, can be re-used by application */
-		smp_store_mb(sqe->flags, 0);
-		qp->sq_get++;
-	} else {
-		rv = 0;
+		spin_unlock(&qp->orq_lock);
 	}
+
+	/* Clear SQE, can be re-used by application */
+	smp_store_mb(sqe->flags, 0);
+	qp->sq_get++;
 out:
 	if (unlikely(rv < 0)) {
 		siw_dbg_qp(qp, "error %d\n", rv);
@@ -1014,6 +968,65 @@ int siw_activate_tx(struct siw_qp *qp)
 	return rv;
 }
 
+/*
+ * Must be called with SQ locked.
+ * To avoid complete SQ starvation by constant inbound READ requests,
+ * the active IRQ will not be served after qp->irq_burst, if the
+ * SQ has pending work.
+ */
+int siw_activate_tx(struct siw_qp *qp)
+{
+	struct siw_sqe *irqe;
+	struct siw_wqe *wqe = tx_wqe(qp);
+
+	if (!qp->attrs.irq_size)
+		return siw_activate_tx_from_sq(qp);
+
+	irqe = &qp->irq[qp->irq_get % qp->attrs.irq_size];
+
+	if (!(irqe->flags & SIW_WQE_VALID))
+		return siw_activate_tx_from_sq(qp);
+
+	/*
+	 * Avoid local WQE processing starvation in case
+	 * of constant inbound READ request stream
+	 */
+	if (sq_get_next(qp) && ++qp->irq_burst >= SIW_IRQ_MAXBURST_SQ_ACTIVE) {
+		qp->irq_burst = 0;
+		return siw_activate_tx_from_sq(qp);
+	}
+	memset(wqe->mem, 0, sizeof(*wqe->mem) * SIW_MAX_SGE);
+	wqe->wr_status = SIW_WR_QUEUED;
+
+	/* start READ RESPONSE */
+	wqe->sqe.opcode = SIW_OP_READ_RESPONSE;
+	wqe->sqe.flags = 0;
+	if (irqe->num_sge) {
+		wqe->sqe.num_sge = 1;
+		wqe->sqe.sge[0].length = irqe->sge[0].length;
+		wqe->sqe.sge[0].laddr = irqe->sge[0].laddr;
+		wqe->sqe.sge[0].lkey = irqe->sge[0].lkey;
+	} else {
+		wqe->sqe.num_sge = 0;
+	}
+
+	/* Retain original RREQ's message sequence number for
+	 * potential error reporting cases.
+	 */
+	wqe->sqe.sge[1].length = irqe->sge[1].length;
+
+	wqe->sqe.rkey = irqe->rkey;
+	wqe->sqe.raddr = irqe->raddr;
+
+	wqe->processed = 0;
+	qp->irq_get++;
+
+	/* mark current IRQ entry free */
+	smp_store_mb(irqe->flags, 0);
+
+	return 1;
+}
+
 /*
  * Check if current CQ state qualifies for calling CQ completion
  * handler. Must be called with CQ lock held.
diff --git a/drivers/infiniband/sw/siw/siw_qp_rx.c b/drivers/infiniband/sw/siw/siw_qp_rx.c
index 4bd1f1f84057..60116f20653c 100644
--- a/drivers/infiniband/sw/siw/siw_qp_rx.c
+++ b/drivers/infiniband/sw/siw/siw_qp_rx.c
@@ -680,6 +680,10 @@ static int siw_init_rresp(struct siw_qp *qp, struct siw_rx_stream *srx)
 	}
 	spin_lock_irqsave(&qp->sq_lock, flags);
 
+	if (unlikely(!qp->attrs.irq_size)) {
+		run_sq = 0;
+		goto error_irq;
+	}
 	if (tx_work->wr_status == SIW_WR_IDLE) {
 		/*
 		 * immediately schedule READ response w/o
@@ -712,8 +716,9 @@ static int siw_init_rresp(struct siw_qp *qp, struct siw_rx_stream *srx)
 		/* RRESP now valid as current TX wqe or placed into IRQ */
 		smp_store_mb(resp->flags, SIW_WQE_VALID);
 	} else {
-		pr_warn("siw: [QP %u]: irq %d exceeded %d\n", qp_id(qp),
-			qp->irq_put % qp->attrs.irq_size, qp->attrs.irq_size);
+error_irq:
+		pr_warn("siw: [QP %u]: IRQ exceeded or null, size %d\n",
+			qp_id(qp), qp->attrs.irq_size);
 
 		siw_init_terminate(qp, TERM_ERROR_LAYER_RDMAP,
 				   RDMAP_ETYPE_REMOTE_OPERATION,
@@ -740,6 +745,9 @@ static int siw_orqe_start_rx(struct siw_qp *qp)
 	struct siw_sqe *orqe;
 	struct siw_wqe *wqe = NULL;
 
+	if (unlikely(!qp->attrs.orq_size))
+		return -EPROTO;
+
 	/* make sure ORQ indices are current */
 	smp_mb();
 
@@ -796,8 +804,8 @@ int siw_proc_rresp(struct siw_qp *qp)
 		 */
 		rv = siw_orqe_start_rx(qp);
 		if (rv) {
-			pr_warn("siw: [QP %u]: ORQ empty at idx %d\n",
-				qp_id(qp), qp->orq_get % qp->attrs.orq_size);
+			pr_warn("siw: [QP %u]: ORQ empty, size %d\n",
+				qp_id(qp), qp->attrs.orq_size);
 			goto error_term;
 		}
 		rv = siw_rresp_check_ntoh(srx, frx);
@@ -1290,11 +1298,13 @@ static int siw_rdmap_complete(struct siw_qp *qp, int error)
 					      wc_status);
 		siw_wqe_put_mem(wqe, SIW_OP_READ);
 
-		if (!error)
+		if (!error) {
 			rv = siw_check_tx_fence(qp);
-		else
-			/* Disable current ORQ eleement */
-			WRITE_ONCE(orq_get_current(qp)->flags, 0);
+		} else {
+			/* Disable current ORQ element */
+			if (qp->attrs.orq_size)
+				WRITE_ONCE(orq_get_current(qp)->flags, 0);
+		}
 		break;
 
 	case RDMAP_RDMA_READ_REQ:
diff --git a/drivers/infiniband/sw/siw/siw_qp_tx.c b/drivers/infiniband/sw/siw/siw_qp_tx.c
index d19d8325588b..7989c4043db4 100644
--- a/drivers/infiniband/sw/siw/siw_qp_tx.c
+++ b/drivers/infiniband/sw/siw/siw_qp_tx.c
@@ -1107,8 +1107,8 @@ int siw_qp_sq_process(struct siw_qp *qp)
 		/*
 		 * RREQ may have already been completed by inbound RRESP!
 		 */
-		if (tx_type == SIW_OP_READ ||
-		    tx_type == SIW_OP_READ_LOCAL_INV) {
+		if ((tx_type == SIW_OP_READ ||
+		     tx_type == SIW_OP_READ_LOCAL_INV) && qp->attrs.orq_size) {
 			/* Cleanup pending entry in ORQ */
 			qp->orq_put--;
 			qp->orq[qp->orq_put % qp->attrs.orq_size].flags = 0;
diff --git a/drivers/infiniband/sw/siw/siw_verbs.c b/drivers/infiniband/sw/siw/siw_verbs.c
index 7cf3242ffb41..fb25e8011f5a 100644
--- a/drivers/infiniband/sw/siw/siw_verbs.c
+++ b/drivers/infiniband/sw/siw/siw_verbs.c
@@ -362,13 +362,23 @@ struct ib_qp *siw_create_qp(struct ib_pd *pd,
 	if (rv)
 		goto err_out;
 
+	num_sqe = attrs->cap.max_send_wr;
+	num_rqe = attrs->cap.max_recv_wr;
+
 	/* All queue indices are derived from modulo operations
 	 * on a free running 'get' (consumer) and 'put' (producer)
 	 * unsigned counter. Having queue sizes at power of two
 	 * avoids handling counter wrap around.
 	 */
-	num_sqe = roundup_pow_of_two(attrs->cap.max_send_wr);
-	num_rqe = roundup_pow_of_two(attrs->cap.max_recv_wr);
+	if (num_sqe)
+		num_sqe = roundup_pow_of_two(num_sqe);
+	else {
+		/* Zero sized SQ is not supported */
+		rv = -EINVAL;
+		goto err_out;
+	}
+	if (num_rqe)
+		num_rqe = roundup_pow_of_two(num_rqe);
 
 	if (udata)
 		qp->sendq = vmalloc_user(num_sqe * sizeof(struct siw_sqe));
@@ -376,7 +386,6 @@ struct ib_qp *siw_create_qp(struct ib_pd *pd,
 		qp->sendq = vzalloc(num_sqe * sizeof(struct siw_sqe));
 
 	if (qp->sendq == NULL) {
-		siw_dbg(base_dev, "SQ size %d alloc failed\n", num_sqe);
 		rv = -ENOMEM;
 		goto err_out_xa;
 	}
@@ -410,7 +419,6 @@ struct ib_qp *siw_create_qp(struct ib_pd *pd,
 			qp->recvq = vzalloc(num_rqe * sizeof(struct siw_rqe));
 
 		if (qp->recvq == NULL) {
-			siw_dbg(base_dev, "RQ size %d alloc failed\n", num_rqe);
 			rv = -ENOMEM;
 			goto err_out_xa;
 		}
@@ -960,9 +968,9 @@ int siw_post_receive(struct ib_qp *base_qp, const struct ib_recv_wr *wr,
 	unsigned long flags;
 	int rv = 0;
 
-	if (qp->srq) {
+	if (qp->srq || qp->attrs.rq_size == 0) {
 		*bad_wr = wr;
-		return -EOPNOTSUPP; /* what else from errno.h? */
+		return -EINVAL;
 	}
 	if (!rdma_is_kernel_res(&qp->base_qp.res)) {
 		siw_dbg_qp(qp, "no kernel post_recv for user mapped rq\n");
-- 
2.17.2



From minwoo.im.dev at gmail.com  Fri Jan  8 09:46:56 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Fri,  8 Jan 2021 23:46:56 +0900
Subject: [PATCH 0/3] nvme: fixes for command retry
Message-ID: <20210108144659.7126-1-minwoo.im.dev@gmail.com>

Hello,

This patchset fixes command retry feature in NVMe core driver.  The
first one supports command retry delay for admin commands also.
Earlier, we only supported I/O commands and this patch made it support
for admin commands too.  The second one fixed checks for whether to
enable Advanced Command Retry Enable(ACRE) or not by checking all
Command Retry Delay Time(CRDT)s from only a single one CRDT[0].  The
last one added a module parameter 'command_retry' to enable the command
retry feature in this driver.

Please review.

Thanks,

Minwoo Im (3):
  nvme: support command retry delay for admin command
  nvme: check all retry delay times in Identify Controller
  nvme: add parameter command_retry to enable retry

 drivers/nvme/host/core.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

-- 
2.17.1



From minwoo.im.dev at gmail.com  Fri Jan  8 09:46:57 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Fri,  8 Jan 2021 23:46:57 +0900
Subject: [PATCH 1/3] nvme: support command retry delay for admin command
In-Reply-To: <20210108144659.7126-1-minwoo.im.dev@gmail.com>
References: <20210108144659.7126-1-minwoo.im.dev@gmail.com>
Message-ID: <20210108144659.7126-2-minwoo.im.dev@gmail.com>

Once driver decides to retry a command that failed, it can have some
delay based on Command Retry Delay(CRD) in Completion Queue Entry.  If
CRD indicates Command Retry Delay Time 1, 2, or 3, driver calcualtes
delay in Identify Controller data structure.

This feature can be applied not only I/O queue commands, but also admin
queue commands.  Admin command during the initialization may fail due to
some un-ready state of a controller, so it would be better to have this
feature for admin commands also.

This patch simply removed getting namespace instance(struct nvme_ns) from
the struct request and get a controller instance(struct nvme_ctrl) by
nvme_req() helper.  Now, nvme_retry_req() calculates the delay
regardless to namespace instance which meant this request is for I/O
command.

Signed-off-by: Minwoo Im <minwoo.im.dev at gmail.com>
---
 drivers/nvme/host/core.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index ce1b61519441..d0c99a9400ea 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -280,14 +280,13 @@ static blk_status_t nvme_error_status(u16 status)
 
 static void nvme_retry_req(struct request *req)
 {
-	struct nvme_ns *ns = req->q->queuedata;
 	unsigned long delay = 0;
 	u16 crd;
 
 	/* The mask and shift result must be <= 3 */
 	crd = (nvme_req(req)->status & NVME_SC_CRD) >> 11;
-	if (ns && crd)
-		delay = ns->ctrl->crdt[crd - 1] * 100;
+	if (crd)
+		delay = nvme_req(req)->ctrl->crdt[crd - 1] * 100;
 
 	nvme_req(req)->retries++;
 	blk_mq_requeue_request(req, false);
-- 
2.17.1



From minwoo.im.dev at gmail.com  Fri Jan  8 09:46:58 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Fri,  8 Jan 2021 23:46:58 +0900
Subject: [PATCH 2/3] nvme: check all retry delay times in Identify Controller
In-Reply-To: <20210108144659.7126-1-minwoo.im.dev@gmail.com>
References: <20210108144659.7126-1-minwoo.im.dev@gmail.com>
Message-ID: <20210108144659.7126-3-minwoo.im.dev@gmail.com>

If none of Command Retry Delay Time(CRDT)s are set, then we can simply
skip to configure Advanced Command Retry Enable(ACRE).

CRDT selection will be made in Completion Queue Entry that controller
has responsibility to decide.

This patch checks all CRDT[0, 1, and 2] in Identify Controller data
structrure instead of checking the first one: CRDT[0].

Signed-off-by: Minwoo Im <minwoo.im.dev at gmail.com>
---
 drivers/nvme/host/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index d0c99a9400ea..6e428fdc25a8 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -2501,7 +2501,7 @@ static int nvme_configure_acre(struct nvme_ctrl *ctrl)
 	int ret;
 
 	/* Don't bother enabling the feature if retry delay is not reported */
-	if (!ctrl->crdt[0])
+	if (!ctrl->crdt[0] && !ctrl->crdt[1] && !ctrl->crdt[2])
 		return 0;
 
 	host = kzalloc(sizeof(*host), GFP_KERNEL);
-- 
2.17.1



From minwoo.im.dev at gmail.com  Fri Jan  8 09:46:59 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Fri,  8 Jan 2021 23:46:59 +0900
Subject: [PATCH 3/3] nvme: add parameter command_retry to enable retry
In-Reply-To: <20210108144659.7126-1-minwoo.im.dev@gmail.com>
References: <20210108144659.7126-1-minwoo.im.dev@gmail.com>
Message-ID: <20210108144659.7126-4-minwoo.im.dev@gmail.com>

nvme_init_request() has set REQ_FAILFAST_DRIVER to make requests
non-retryable.  This command flag value is checked in
nvme_decide_disposition() to decide whether to RETRY or other
operations.  In that point, blk_noretry_request() macro will be used to
check if command flags have one of REQ_FAILFAST_*.  If so, it just
decides to complete the request without retrying.

This patch added a module parameter named command_retry to turn on the
command retry feature in this driver.  If turning it on,
REQ3_FAILFAST_DRIVER will not be set to requests so that retry can be
reached out to nvme_retry_req() based on the module parameter.

Signed-off-by: Minwoo Im <minwoo.im.dev at gmail.com>
---
 drivers/nvme/host/core.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 6e428fdc25a8..e1836ca9956f 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -44,6 +44,10 @@ static unsigned char shutdown_timeout = 5;
 module_param(shutdown_timeout, byte, 0644);
 MODULE_PARM_DESC(shutdown_timeout, "timeout in seconds for controller shutdown");
 
+static bool command_retry;
+module_param(command_retry, bool, 0644);
+MODULE_PARM_DESC(command_retry, "retry commands up to nvme_max_retries");
+
 static u8 nvme_max_retries = 5;
 module_param_named(max_retries, nvme_max_retries, byte, 0644);
 MODULE_PARM_DESC(max_retries, "max number of retries a command may have");
@@ -560,7 +564,8 @@ static inline void nvme_init_request(struct request *req,
 	else /* no queuedata implies admin queue */
 		req->timeout = NVME_ADMIN_TIMEOUT;
 
-	req->cmd_flags |= REQ_FAILFAST_DRIVER;
+	if (!command_retry)
+		req->cmd_flags |= REQ_FAILFAST_DRIVER;
 	nvme_clear_nvme_request(req);
 	nvme_req(req)->cmd = cmd;
 }
-- 
2.17.1



From sagi at grimberg.me  Fri Jan  8 15:20:15 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Fri, 8 Jan 2021 12:20:15 -0800
Subject: [PATCH] nvme-tcp: Fix possible race of io_work and direct send
In-Reply-To: <CAJ3xEMj8Y_=Y=orV59GR9=L4M3r4+mZzMW6w2cv2K9d5eKXZDA@mail.gmail.com>
References: <20201221080339.945164-1-sagi@grimberg.me>
 <CAJ3xEMj8Y_=Y=orV59GR9=L4M3r4+mZzMW6w2cv2K9d5eKXZDA@mail.gmail.com>
Message-ID: <e206eb55-8792-b9c2-64cb-bd76ed09e12e@grimberg.me>


>> --- a/drivers/nvme/host/tcp.c
>> +++ b/drivers/nvme/host/tcp.c
> 
>> @@ -279,7 +289,7 @@ static inline void nvme_tcp_queue_request(struct nvme_tcp_request *req,
>>          if (queue->io_cpu == smp_processor_id() &&
>>              sync && empty && mutex_trylock(&queue->send_mutex)) {
> 
> but we can't rely on the processor id if we are on preemptible state..
> 
>    373.940336] BUG: using smp_processor_id() in preemptible [00000000]
> code: kworker/u8:4/457
> [  373.942037] caller is nvme_tcp_submit_async_event+0x4da/0x690 [nvme_tcp]
> [  373.942144] CPU: 0 PID: 457 Comm: kworker/u8:4 Not tainted 5.11.0-rc1+ #116
> [  373.942171] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),
> BIOS rel-1.12.1-0-ga5cab58e9a3f-prebuilt.qemu.org 04/01/2014
> [  373.942196] Workqueue: nvme-wq nvme_async_event_work [nvme_core]
> [  373.942259] Call Trace:
> [  373.942286]  dump_stack+0xd0/0x119
> [  373.942346]  check_preemption_disabled+0xec/0xf0
> [  373.942397]  nvme_tcp_submit_async_event+0x4da/0x690 [nvme_tcp]
> [  373.942449]  nvme_async_event_work+0x11d/0x1f0 [nvme_core]
> [  373.942496]  ? nvme_ctrl_loss_tmo_show+0x140/0x140 [nvme_core]
> [  373.942576]  process_one_work+0x9f3/0x1630
> [  373.942649]  ? pwq_dec_nr_in_flight+0x330/0x330
> [  373.942765]  worker_thread+0x9e/0xf60
> [  373.942849]  ? process_one_work+0x1630/0x1630
> [  373.942889]  kthread+0x362/0x480
> [  373.942918]  ? kthread_create_on_node+0x100/0x100

Well, this is a heuristic anyways, too bad we need to
disable preemption just for this...

I'm assuming that this makes the issue go away?
--
diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index cf856103025a..ea07336ca179 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -281,8 +281,11 @@ static inline void nvme_tcp_queue_request(struct 
nvme_tcp_request *req,
                 bool sync, bool last)
  {
         struct nvme_tcp_queue *queue = req->queue;
+       int cpu;
         bool empty;

+       cpu = get_cpu();
+       put_cpu();
         empty = llist_add(&req->lentry, &queue->req_list) &&
                 list_empty(&queue->send_list) && !queue->request;

@@ -291,8 +294,8 @@ static inline void nvme_tcp_queue_request(struct 
nvme_tcp_request *req,
          * directly, otherwise queue io_work. Also, only do that if we
          * are on the same cpu, so we don't introduce contention.
          */
-       if (queue->io_cpu == smp_processor_id() &&
-           sync && empty && mutex_trylock(&queue->send_mutex)) {
+       if (queue->io_cpu == cpu && sync && empty &&
+           mutex_trylock(&queue->send_mutex)) {
                 queue->more_requests = !last;
                 nvme_tcp_send_all(queue);
                 queue->more_requests = false;

--


From sagi at grimberg.me  Fri Jan  8 15:23:59 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Fri, 8 Jan 2021 12:23:59 -0800
Subject: kernel panic in nvmet_tcp when receiving malformed admin command
In-Reply-To: <dec5fc1d-62d6-1c1e-e2f8-4aa5aeb084af@grimberg.me>
References: <BL0PR1901MB2067C827A2D826C0FBFE985591320@BL0PR1901MB2067.namprd19.prod.outlook.com>
 <cee26269-c9c3-7ce7-8486-4ed16a632e44@grimberg.me>
 <BL0PR1901MB20671CF789D8C246AF911B4D91330@BL0PR1901MB2067.namprd19.prod.outlook.com>
 <DS7PR19MB4439372515F931BA5A1578ABEED30@DS7PR19MB4439.namprd19.prod.outlook.com>
 <dec5fc1d-62d6-1c1e-e2f8-4aa5aeb084af@grimberg.me>
Message-ID: <2f2b2df4-ba06-a7ae-23cf-31eb17998c6e@grimberg.me>


>> Hi Sagi, is the patch addressing the below issue is already out there?
> 
> No, thanks for reminding me, I'll have a look into this.

Amit, Ran,

Does this solve your issue?
This needs to split to patches but would be good to understand
if this works.
--
diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
index dc1f0f647189..c41902f7ce39 100644
--- a/drivers/nvme/target/tcp.c
+++ b/drivers/nvme/target/tcp.c
@@ -204,7 +204,6 @@ nvmet_tcp_get_cmd(struct nvmet_tcp_queue *queue)
         cmd->rbytes_done = cmd->wbytes_done = 0;
         cmd->pdu_len = 0;
         cmd->pdu_recv = 0;
-       cmd->iov = NULL;
         cmd->flags = 0;
         return cmd;
  }
@@ -294,6 +293,7 @@ static void nvmet_tcp_unmap_pdu_iovec(struct 
nvmet_tcp_cmd *cmd)

         for (i = 0; i < cmd->nr_mapped; i++)
                 kunmap(sg_page(&sg[i]));
+       cmd->nr_mapped = 0;
  }

  static void nvmet_tcp_map_pdu_iovec(struct nvmet_tcp_cmd *cmd)
@@ -341,6 +341,14 @@ static void nvmet_tcp_socket_error(struct 
nvmet_tcp_queue *queue, int status)
                 nvmet_tcp_fatal_error(queue);
  }

+static void nvmet_tcp_unmap_data(struct nvmet_tcp_cmd *cmd)
+{
+       kfree(cmd->iov);
+       cmd->iov = NULL;
+       sgl_free(cmd->req.sg);
+       cmd->req.sg = NULL;
+}
+
  static int nvmet_tcp_map_data(struct nvmet_tcp_cmd *cmd)
  {
         struct nvme_sgl_desc *sgl = &cmd->req.cmd->common.dptr.sgl;
@@ -375,6 +383,7 @@ static int nvmet_tcp_map_data(struct nvmet_tcp_cmd *cmd)
         return 0;
  err:
         sgl_free(cmd->req.sg);
+       cmd->req.sg = NULL;
         return NVME_SC_INTERNAL;
  }

@@ -571,17 +580,13 @@ static int nvmet_try_send_data(struct 
nvmet_tcp_cmd *cmd, bool last_in_batch)
         } else {
                 if (queue->nvme_sq.sqhd_disabled) {
                         cmd->queue->snd_cmd = NULL;
+                       nvmet_tcp_unmap_data(cmd);
                         nvmet_tcp_put_cmd(cmd);
                 } else {
                         nvmet_setup_response_pdu(cmd);
                 }
         }

-       if (queue->nvme_sq.sqhd_disabled) {
-               kfree(cmd->iov);
-               sgl_free(cmd->req.sg);
-       }
-
         return 1;

  }
@@ -609,9 +614,8 @@ static int nvmet_try_send_response(struct 
nvmet_tcp_cmd *cmd,
         if (left)
                 return -EAGAIN;

-       kfree(cmd->iov);
-       sgl_free(cmd->req.sg);
         cmd->queue->snd_cmd = NULL;
+       nvmet_tcp_unmap_data(cmd);
         nvmet_tcp_put_cmd(cmd);
         return 1;
  }
@@ -665,6 +669,7 @@ static int nvmet_try_send_ddgst(struct nvmet_tcp_cmd 
*cmd, bool last_in_batch)

         if (queue->nvme_sq.sqhd_disabled) {
                 cmd->queue->snd_cmd = NULL;
+               nvmet_tcp_unmap_data(cmd);
                 nvmet_tcp_put_cmd(cmd);
         } else {
                 nvmet_setup_response_pdu(cmd);
@@ -1082,15 +1087,16 @@ static int nvmet_tcp_try_recv_data(struct 
nvmet_tcp_queue *queue)

         nvmet_tcp_unmap_pdu_iovec(cmd);

-       if (!(cmd->flags & NVMET_TCP_F_INIT_FAILED) &&
-           cmd->rbytes_done == cmd->req.transfer_len) {
-               if (queue->data_digest) {
-                       nvmet_tcp_prep_recv_ddgst(cmd);
-                       return 0;
-               }
-               cmd->req.execute(&cmd->req);
+       if (queue->data_digest) {
+               nvmet_tcp_prep_recv_ddgst(cmd);
+               return 0;
         }

+       if (unlikely(cmd->flags & NVMET_TCP_F_INIT_FAILED))
+               nvmet_tcp_finish_cmd(cmd);
+       else if (cmd->rbytes_done == cmd->req.transfer_len)
+               cmd->req.execute(&cmd->req);
+
         nvmet_prepare_receive_pdu(queue);
         return 0;
  }
@@ -1120,14 +1126,16 @@ static int nvmet_tcp_try_recv_ddgst(struct 
nvmet_tcp_queue *queue)
                         queue->idx, cmd->req.cmd->common.command_id,
                         queue->pdu.cmd.hdr.type, 
le32_to_cpu(cmd->recv_ddgst),
                         le32_to_cpu(cmd->exp_ddgst));
+               nvmet_req_uninit(&cmd->req);
                 nvmet_tcp_finish_cmd(cmd);
                 nvmet_tcp_fatal_error(queue);
                 ret = -EPROTO;
                 goto out;
         }

-       if (!(cmd->flags & NVMET_TCP_F_INIT_FAILED) &&
-           cmd->rbytes_done == cmd->req.transfer_len)
+       if (unlikely(cmd->flags & NVMET_TCP_F_INIT_FAILED))
+               nvmet_tcp_finish_cmd(cmd);
+       else if (cmd->rbytes_done == cmd->req.transfer_len)
                 cmd->req.execute(&cmd->req);
         ret = 0;
  out:
@@ -1139,7 +1147,8 @@ static int nvmet_tcp_try_recv_one(struct 
nvmet_tcp_queue *queue)
  {
         int result = 0;

-       if (unlikely(queue->rcv_state == NVMET_TCP_RECV_ERR))
+       if (unlikely(queue->rcv_state == NVMET_TCP_RECV_ERR ||
+                    queue->state == NVMET_TCP_Q_DISCONNECTING))
                 return 0;

         if (queue->rcv_state == NVMET_TCP_RECV_PDU) {
@@ -1333,10 +1342,26 @@ static void 
nvmet_tcp_restore_socket_callbacks(struct nvmet_tcp_queue *queue)

  static void nvmet_tcp_finish_cmd(struct nvmet_tcp_cmd *cmd)
  {
-       nvmet_req_uninit(&cmd->req);
         nvmet_tcp_unmap_pdu_iovec(cmd);
-       kfree(cmd->iov);
-       sgl_free(cmd->req.sg);
+       nvmet_tcp_unmap_data(cmd);
+       nvmet_tcp_put_cmd(cmd);
+}
+
+static void nvmet_tcp_unmap_cmds(struct nvmet_tcp_queue *queue)
+{
+       struct nvmet_tcp_cmd *cmd = queue->cmds;
+       int i;
+
+       for (i = 0; i < queue->nr_cmds; i++, cmd++) {
+               nvmet_tcp_unmap_pdu_iovec(cmd);
+               nvmet_tcp_unmap_data(cmd);
+       }
+
+       if (!queue->nr_cmds) {
+               /* failed in connect */
+               nvmet_tcp_unmap_pdu_iovec(cmd);
+               nvmet_tcp_unmap_data(cmd);
+       }
  }

  static void nvmet_tcp_uninit_data_in_cmds(struct nvmet_tcp_queue *queue)
@@ -1346,12 +1371,12 @@ static void nvmet_tcp_uninit_data_in_cmds(struct 
nvmet_tcp_queue *queue)

         for (i = 0; i < queue->nr_cmds; i++, cmd++) {
                 if (nvmet_tcp_need_data_in(cmd))
-                       nvmet_tcp_finish_cmd(cmd);
+                       nvmet_req_uninit(&cmd->req);
         }

         if (!queue->nr_cmds && nvmet_tcp_need_data_in(&queue->connect)) {
                 /* failed in connect */
-               nvmet_tcp_finish_cmd(&queue->connect);
+               nvmet_req_uninit(&cmd->req);
         }
  }

@@ -1370,6 +1395,7 @@ static void nvmet_tcp_release_queue_work(struct 
work_struct *w)
         nvmet_tcp_uninit_data_in_cmds(queue);
         nvmet_sq_destroy(&queue->nvme_sq);
         cancel_work_sync(&queue->io_work);
+       nvmet_tcp_unmap_cmds(queue);
         sock_release(queue->sock);
         nvmet_tcp_free_cmds(queue);
         if (queue->hdr_digest || queue->data_digest)
--


From jgg at nvidia.com  Fri Jan  8 15:38:32 2021
From: jgg at nvidia.com (Jason Gunthorpe)
Date: Fri, 8 Jan 2021 16:38:32 -0400
Subject: [PATCH v4] RDMA/siw: Fix handling of zero-sized Read and Receive
 Queues.
In-Reply-To: <20210108125845.1803-1-bmt@zurich.ibm.com>
References: <20210108125845.1803-1-bmt@zurich.ibm.com>
Message-ID: <20210108203832.GA1050149@nvidia.com>

On Fri, Jan 08, 2021 at 01:58:45PM +0100, Bernard Metzler wrote:
> During connection setup, the application may choose to zero-size
> inbound and outbound READ queues, as well as the Receive queue.
> This patch fixes handling of zero-sized queues, but not prevents
> it.
> 
> Kamal Heib says in an initial error report:
> When running the blktests over siw the following shift-out-of-bounds is
> reported, this is happening because the passed IRD or ORD from the ulp
> could be zero which will lead to unexpected behavior when calling
> roundup_pow_of_two(), fix that by blocking zero values of ORD or IRD.
> 
> UBSAN: shift-out-of-bounds in ./include/linux/log2.h:57:13
> shift exponent 64 is too large for 64-bit type 'long unsigned int'
> CPU: 20 PID: 3957 Comm: kworker/u64:13 Tainted: G S     5.10.0-rc6 #2
> Hardware name: Dell Inc. PowerEdge R630/02C2CP, BIOS 2.1.5 04/11/2016
> Workqueue: iw_cm_wq cm_work_handler [iw_cm]
> Call Trace:
>  dump_stack+0x99/0xcb
>  ubsan_epilogue+0x5/0x40
>  __ubsan_handle_shift_out_of_bounds.cold.11+0xb4/0xf3
>  ? down_write+0x183/0x3d0
>  siw_qp_modify.cold.8+0x2d/0x32 [siw]
>  ? __local_bh_enable_ip+0xa5/0xf0
>  siw_accept+0x906/0x1b60 [siw]
>  ? xa_load+0x147/0x1f0
>  ? siw_connect+0x17a0/0x17a0 [siw]
>  ? lock_downgrade+0x700/0x700
>  ? siw_get_base_qp+0x1c2/0x340 [siw]
>  ? _raw_spin_unlock_irqrestore+0x39/0x40
>  iw_cm_accept+0x1f4/0x430 [iw_cm]
>  rdma_accept+0x3fa/0xb10 [rdma_cm]
>  ? check_flush_dependency+0x410/0x410
>  ? cma_rep_recv+0x570/0x570 [rdma_cm]
>  nvmet_rdma_queue_connect+0x1a62/0x2680 [nvmet_rdma]
>  ? nvmet_rdma_alloc_cmds+0xce0/0xce0 [nvmet_rdma]
>  ? lock_release+0x56e/0xcc0
>  ? lock_downgrade+0x700/0x700
>  ? lock_downgrade+0x700/0x700
>  ? __xa_alloc_cyclic+0xef/0x350
>  ? __xa_alloc+0x2d0/0x2d0
>  ? rdma_restrack_add+0xbe/0x2c0 [ib_core]
>  ? __ww_mutex_die+0x190/0x190
>  cma_cm_event_handler+0xf2/0x500 [rdma_cm]
>  iw_conn_req_handler+0x910/0xcb0 [rdma_cm]
>  ? _raw_spin_unlock_irqrestore+0x39/0x40
>  ? trace_hardirqs_on+0x1c/0x150
>  ? cma_ib_handler+0x8a0/0x8a0 [rdma_cm]
>  ? __kasan_kmalloc.constprop.7+0xc1/0xd0
>  cm_work_handler+0x121c/0x17a0 [iw_cm]
>  ? iw_cm_reject+0x190/0x190 [iw_cm]
>  ? trace_hardirqs_on+0x1c/0x150
>  process_one_work+0x8fb/0x16c0
>  ? pwq_dec_nr_in_flight+0x320/0x320
>  worker_thread+0x87/0xb40
>  ? __kthread_parkme+0xd1/0x1a0
>  ? process_one_work+0x16c0/0x16c0
>  kthread+0x35f/0x430
>  ? kthread_mod_delayed_work+0x180/0x180
>  ret_from_fork+0x22/0x30
> 
> Fixes: a531975279f3 ("rdma/siw: main include file")
> Fixes: f29dd55b0236 ("rdma/siw: queue pair methods")
> Fixes: 8b6a361b8c48 ("rdma/siw: receive path")
> Fixes: b9be6f18cf9e ("rdma/siw: transmit path")
> Fixes: 303ae1cdfdf7 ("rdma/siw: application interface")
> Reported-by: Kamal Heib <kamalheib1 at gmail.com>
> Reported-by: Yi Zhang <yi.zhang at redhat.com>
> Reported-by: kernel test robot <lkp at intel.com>
> Signed-off-by: Bernard Metzler <bmt at zurich.ibm.com>
> ---
> v2 changes:
> - Fix uninitialized variable introduced in siw_qp_rx.c, as
>   Reported-by: kernel test robot <lkp at intel.com>
> - Add initial error report as
>   Reported-by: Kamal Heib <kamalheib1 at gmail.com>
> 
> v3 changes:
> - correct patch changelog location
> - remove prints for failed queue malloc's as pointed out by
>   Leon Romanovsky
> 
> v4 changes:
> - unwind siw_activate_tx function avoiding confusing
>   goto's as requested by Jason Gunthorp
> 
>  drivers/infiniband/sw/siw/siw.h       |   2 +-
>  drivers/infiniband/sw/siw/siw_qp.c    | 271 ++++++++++++++------------
>  drivers/infiniband/sw/siw/siw_qp_rx.c |  26 ++-
>  drivers/infiniband/sw/siw/siw_qp_tx.c |   4 +-
>  drivers/infiniband/sw/siw/siw_verbs.c |  20 +-
>  5 files changed, 177 insertions(+), 146 deletions(-)

Applied to for-next, thanks

Jason


From kbusch at kernel.org  Fri Jan  8 17:34:31 2021
From: kbusch at kernel.org (Keith Busch)
Date: Fri, 8 Jan 2021 14:34:31 -0800
Subject: [PATCH] nvme: trace: parse format nvm command in detail
In-Reply-To: <20210106090053.GA32643@lst.de>
References: <20210104155343.GA26034@michal-desk>
 <20210104160220.GB1024941@dhcp-10-100-145-180.wdc.com>
 <20210106090053.GA32643@lst.de>
Message-ID: <20210108223431.GA1451691@dhcp-10-100-145-180.wdc.com>

On Wed, Jan 06, 2021 at 10:00:53AM +0100, Christoph Hellwig wrote:
> On Mon, Jan 04, 2021 at 08:02:20AM -0800, Keith Busch wrote:
> > Perhaps it's too late since we've already gone done this path in the
> > driver, but IMO, we should have only traced raw dwords without any
> > additional decoding. This would have allowed consistent output for all
> > kernel versions and resilient to future spec changes. Then that could
> > have made possible for a user space utility to do the decoding to a
> > human friendly format, kind of like what blkparse does for block layer
> > trace events.
> 
> the block tracepoints actually contain pretty detailed decoding as well.

Sure, but what I'm trying to say is that the current nvme decoding isn't
forward compatible with spec changes that tools will be able to use, and
will not be possible to see currently reserved fields. It will be a
never ending maintenance burden to chase those changes, and there will
be no consistency in nvme trace events for different kernel versions.

If it would help at all to move in a more future proof direction, I
wrote a little script handling all the decoding and posted it here:

  https://github.com/linux-nvme/nvme-trace/blob/main/nvme-trace.pl

If that's okay, we can greatly simplify the nvme tracing so that it
will always be consistent and able to obtain new command fields as they
show up.


From rikard.falkeborn at gmail.com  Fri Jan  8 18:41:47 2021
From: rikard.falkeborn at gmail.com (Rikard Falkeborn)
Date: Sat,  9 Jan 2021 00:41:47 +0100
Subject: [PATCH] nvme: Constify static attribute_group structs
Message-ID: <20210108234147.42151-1-rikard.falkeborn@gmail.com>

The only usage of these is to put their addresses in arrays of pointers
to const attribute_groups. Make them const to allow the compiler to put
them in read-only memory.

Signed-off-by: Rikard Falkeborn <rikard.falkeborn at gmail.com>
---
 drivers/nvme/host/core.c     | 4 ++--
 drivers/nvme/host/fc.c       | 2 +-
 drivers/nvme/target/fcloop.c | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index ce1b61519441..fc3743de53be 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -2849,7 +2849,7 @@ static struct attribute *nvme_subsys_attrs[] = {
 	NULL,
 };
 
-static struct attribute_group nvme_subsys_attrs_group = {
+static const struct attribute_group nvme_subsys_attrs_group = {
 	.attrs = nvme_subsys_attrs,
 };
 
@@ -3679,7 +3679,7 @@ static umode_t nvme_dev_attrs_are_visible(struct kobject *kobj,
 	return a->mode;
 }
 
-static struct attribute_group nvme_dev_attrs_group = {
+static const struct attribute_group nvme_dev_attrs_group = {
 	.attrs		= nvme_dev_attrs,
 	.is_visible	= nvme_dev_attrs_are_visible,
 };
diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c
index 38373a0e86ef..5d3976116558 100644
--- a/drivers/nvme/host/fc.c
+++ b/drivers/nvme/host/fc.c
@@ -3776,7 +3776,7 @@ static struct attribute *nvme_fc_attrs[] = {
 	NULL
 };
 
-static struct attribute_group nvme_fc_attr_group = {
+static const struct attribute_group nvme_fc_attr_group = {
 	.attrs = nvme_fc_attrs,
 };
 
diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c
index 733d9363900e..9a0bd9af3f9a 100644
--- a/drivers/nvme/target/fcloop.c
+++ b/drivers/nvme/target/fcloop.c
@@ -1544,7 +1544,7 @@ static struct attribute *fcloop_dev_attrs[] = {
 	NULL
 };
 
-static struct attribute_group fclopp_dev_attrs_group = {
+static const struct attribute_group fclopp_dev_attrs_group = {
 	.attrs		= fcloop_dev_attrs,
 };
 
-- 
2.30.0



From dan.j.williams at intel.com  Fri Jan  8 19:12:31 2021
From: dan.j.williams at intel.com (Dan Williams)
Date: Fri, 8 Jan 2021 16:12:31 -0800
Subject: [PATCH] nvme: trace: parse format nvm command in detail
In-Reply-To: <20210108223431.GA1451691@dhcp-10-100-145-180.wdc.com>
References: <20210104155343.GA26034@michal-desk>
 <20210104160220.GB1024941@dhcp-10-100-145-180.wdc.com>
 <20210106090053.GA32643@lst.de>
 <20210108223431.GA1451691@dhcp-10-100-145-180.wdc.com>
Message-ID: <CAPcyv4jLWOKDTyGzwar4C0H5euggvD_Ak6NESLd9=1THGC=ASg@mail.gmail.com>

On Fri, Jan 8, 2021 at 2:34 PM Keith Busch <kbusch at kernel.org> wrote:
>
> On Wed, Jan 06, 2021 at 10:00:53AM +0100, Christoph Hellwig wrote:
> > On Mon, Jan 04, 2021 at 08:02:20AM -0800, Keith Busch wrote:
> > > Perhaps it's too late since we've already gone done this path in the
> > > driver, but IMO, we should have only traced raw dwords without any
> > > additional decoding. This would have allowed consistent output for all
> > > kernel versions and resilient to future spec changes. Then that could
> > > have made possible for a user space utility to do the decoding to a
> > > human friendly format, kind of like what blkparse does for block layer
> > > trace events.
> >
> > the block tracepoints actually contain pretty detailed decoding as well.
>
> Sure, but what I'm trying to say is that the current nvme decoding isn't
> forward compatible with spec changes that tools will be able to use, and
> will not be possible to see currently reserved fields. It will be a
> never ending maintenance burden to chase those changes, and there will
> be no consistency in nvme trace events for different kernel versions.
>
> If it would help at all to move in a more future proof direction, I
> wrote a little script handling all the decoding and posted it here:
>
>   https://github.com/linux-nvme/nvme-trace/blob/main/nvme-trace.pl
>
> If that's okay, we can greatly simplify the nvme tracing so that it
> will always be consistent and able to obtain new command fields as they
> show up.

Is there a more centralized place to land such a helper? trace-cmd,
perf? The nice thing about kernel parsing is I don't need to have a
separate pile of disparate tools across subsystems.


From yi.zhang at redhat.com  Fri Jan  8 20:59:45 2021
From: yi.zhang at redhat.com (Yi Zhang)
Date: Sat, 9 Jan 2021 09:59:45 +0800
Subject: [PATCH] nvme-tcp: Fix possible race of io_work and direct send
In-Reply-To: <e206eb55-8792-b9c2-64cb-bd76ed09e12e@grimberg.me>
References: <20201221080339.945164-1-sagi@grimberg.me>
 <CAJ3xEMj8Y_=Y=orV59GR9=L4M3r4+mZzMW6w2cv2K9d5eKXZDA@mail.gmail.com>
 <e206eb55-8792-b9c2-64cb-bd76ed09e12e@grimberg.me>
Message-ID: <7f47bbab-9a32-3982-be56-6389148470ca@redhat.com>



On 1/9/21 4:20 AM, Sagi Grimberg wrote:
>
>>> --- a/drivers/nvme/host/tcp.c
>>> +++ b/drivers/nvme/host/tcp.c
>>
>>> @@ -279,7 +289,7 @@ static inline void nvme_tcp_queue_request(struct 
>>> nvme_tcp_request *req,
>>> ???????? if (queue->io_cpu == smp_processor_id() &&
>>> ???????????? sync && empty && mutex_trylock(&queue->send_mutex)) {
>>
>> but we can't rely on the processor id if we are on preemptible state..
>>
>> ?? 373.940336] BUG: using smp_processor_id() in preemptible [00000000]
>> code: kworker/u8:4/457
>> [? 373.942037] caller is nvme_tcp_submit_async_event+0x4da/0x690 
>> [nvme_tcp]
>> [? 373.942144] CPU: 0 PID: 457 Comm: kworker/u8:4 Not tainted 
>> 5.11.0-rc1+ #116
>> [? 373.942171] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),
>> BIOS rel-1.12.1-0-ga5cab58e9a3f-prebuilt.qemu.org 04/01/2014
>> [? 373.942196] Workqueue: nvme-wq nvme_async_event_work [nvme_core]
>> [? 373.942259] Call Trace:
>> [? 373.942286]? dump_stack+0xd0/0x119
>> [? 373.942346]? check_preemption_disabled+0xec/0xf0
>> [? 373.942397]? nvme_tcp_submit_async_event+0x4da/0x690 [nvme_tcp]
>> [? 373.942449]? nvme_async_event_work+0x11d/0x1f0 [nvme_core]
>> [? 373.942496]? ? nvme_ctrl_loss_tmo_show+0x140/0x140 [nvme_core]
>> [? 373.942576]? process_one_work+0x9f3/0x1630
>> [? 373.942649]? ? pwq_dec_nr_in_flight+0x330/0x330
>> [? 373.942765]? worker_thread+0x9e/0xf60
>> [? 373.942849]? ? process_one_work+0x1630/0x1630
>> [? 373.942889]? kthread+0x362/0x480
>> [? 373.942918]? ? kthread_create_on_node+0x100/0x100
>
> Well, this is a heuristic anyways, too bad we need to
> disable preemption just for this...
>
> I'm assuming that this makes the issue go away?
> -- 
> diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
> index cf856103025a..ea07336ca179 100644
> --- a/drivers/nvme/host/tcp.c
> +++ b/drivers/nvme/host/tcp.c
> @@ -281,8 +281,11 @@ static inline void nvme_tcp_queue_request(struct 
> nvme_tcp_request *req,
> ??????????????? bool sync, bool last)
> ?{
> ??????? struct nvme_tcp_queue *queue = req->queue;
> +?????? int cpu;
> ??????? bool empty;
>
> +?????? cpu = get_cpu();
> +?????? put_cpu();
> ??????? empty = llist_add(&req->lentry, &queue->req_list) &&
> ??????????????? list_empty(&queue->send_list) && !queue->request;
>
> @@ -291,8 +294,8 @@ static inline void nvme_tcp_queue_request(struct 
> nvme_tcp_request *req,
> ???????? * directly, otherwise queue io_work. Also, only do that if we
> ???????? * are on the same cpu, so we don't introduce contention.
> ???????? */
> -?????? if (queue->io_cpu == smp_processor_id() &&
> -?????????? sync && empty && mutex_trylock(&queue->send_mutex)) {
> +?????? if (queue->io_cpu == cpu && sync && empty &&
> +?????????? mutex_trylock(&queue->send_mutex)) {
> ??????????????? queue->more_requests = !last;
> ??????????????? nvme_tcp_send_all(queue);
> ??????????????? queue->more_requests = false;
>
Hi Sagi
Thanks for the quick response, confirmed the issue was fixed, feel free 
to add:

Tested-by: Yi Zhang <yi.zhang at redhat.com>

> -- 
>
> _______________________________________________
> Linux-nvme mailing list
> Linux-nvme at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-nvme
>



From lkp at intel.com  Sat Jan  9 01:42:26 2021
From: lkp at intel.com (kernel test robot)
Date: Sat, 09 Jan 2021 14:42:26 +0800
Subject: [linux-nvme:nvme-5.11] BUILD SUCCESS
 2b59787a223b79228fed9ade1bf6936194ddb8cd
Message-ID: <5ff95052.5ksgQR0a/QuMD5hl%lkp@intel.com>

tree/branch: git://git.infradead.org/nvme.git  nvme-5.11
branch HEAD: 2b59787a223b79228fed9ade1bf6936194ddb8cd  nvme: remove the unused status argument from nvme_trace_bio_complete

elapsed time: 723m

configs tested: 146
configs skipped: 2

The following configs have been built successfully.
More configs may be tested in the coming days.

gcc tested configs:
arm                                 defconfig
arm64                            allyesconfig
arm64                               defconfig
arm                              allyesconfig
arm                              allmodconfig
powerpc                      mgcoge_defconfig
mips                      malta_kvm_defconfig
m68k                        mvme16x_defconfig
powerpc                         wii_defconfig
riscv                          rv32_defconfig
mips                           ip28_defconfig
riscv                            alldefconfig
mips                        jmr3927_defconfig
arm                           spitz_defconfig
arm                        magician_defconfig
sh                            migor_defconfig
arm                         socfpga_defconfig
powerpc                       ebony_defconfig
mips                         bigsur_defconfig
arm                        realview_defconfig
m68k                        m5307c3_defconfig
mips                            gpr_defconfig
powerpc                     tqm8540_defconfig
powerpc                  iss476-smp_defconfig
powerpc                    sam440ep_defconfig
mips                         tb0219_defconfig
mips                      bmips_stb_defconfig
powerpc                      ppc6xx_defconfig
mips                  decstation_64_defconfig
mips                        workpad_defconfig
mips                        omega2p_defconfig
sh                            titan_defconfig
powerpc                      ppc64e_defconfig
sh                        dreamcast_defconfig
powerpc                           allnoconfig
arm                         lpc18xx_defconfig
arm                        mvebu_v7_defconfig
microblaze                          defconfig
arm                        oxnas_v6_defconfig
m68k                                defconfig
m68k                         apollo_defconfig
powerpc64                           defconfig
arm                       cns3420vb_defconfig
m68k                        mvme147_defconfig
sh                            shmin_defconfig
sh                             sh03_defconfig
powerpc                      ppc40x_defconfig
arm                      jornada720_defconfig
mips                         tb0287_defconfig
arm                       mainstone_defconfig
arm                           h3600_defconfig
c6x                                 defconfig
xtensa                  audio_kc705_defconfig
arm                          pxa3xx_defconfig
riscv                    nommu_virt_defconfig
sh                           se7619_defconfig
riscv                            allmodconfig
mips                           ip22_defconfig
powerpc                  mpc885_ads_defconfig
mips                malta_kvm_guest_defconfig
powerpc                       ppc64_defconfig
powerpc                     tqm8560_defconfig
mips                         cobalt_defconfig
arm                       aspeed_g5_defconfig
m68k                       m5249evb_defconfig
mips                      maltaaprp_defconfig
arc                          axs103_defconfig
arm                     eseries_pxa_defconfig
sh                          r7780mp_defconfig
powerpc                      acadia_defconfig
arc                          axs101_defconfig
mips                           gcw0_defconfig
mips                      pic32mzda_defconfig
parisc                generic-32bit_defconfig
powerpc                mpc7448_hpc2_defconfig
mips                      pistachio_defconfig
arm                    vt8500_v6_v7_defconfig
powerpc                      chrp32_defconfig
arm                          lpd270_defconfig
mips                           ci20_defconfig
ia64                             allmodconfig
ia64                                defconfig
ia64                             allyesconfig
m68k                             allmodconfig
m68k                             allyesconfig
nios2                               defconfig
arc                              allyesconfig
nds32                             allnoconfig
c6x                              allyesconfig
nds32                               defconfig
nios2                            allyesconfig
csky                                defconfig
alpha                               defconfig
alpha                            allyesconfig
xtensa                           allyesconfig
h8300                            allyesconfig
arc                                 defconfig
sh                               allmodconfig
parisc                              defconfig
s390                             allyesconfig
parisc                           allyesconfig
s390                                defconfig
i386                             allyesconfig
sparc                            allyesconfig
sparc                               defconfig
i386                               tinyconfig
i386                                defconfig
mips                             allyesconfig
mips                             allmodconfig
powerpc                          allyesconfig
powerpc                          allmodconfig
x86_64               randconfig-a004-20210108
x86_64               randconfig-a006-20210108
x86_64               randconfig-a001-20210108
x86_64               randconfig-a002-20210108
x86_64               randconfig-a003-20210108
x86_64               randconfig-a005-20210108
i386                 randconfig-a005-20210108
i386                 randconfig-a002-20210108
i386                 randconfig-a001-20210108
i386                 randconfig-a003-20210108
i386                 randconfig-a006-20210108
i386                 randconfig-a004-20210108
i386                 randconfig-a016-20210108
i386                 randconfig-a011-20210108
i386                 randconfig-a014-20210108
i386                 randconfig-a015-20210108
i386                 randconfig-a013-20210108
i386                 randconfig-a012-20210108
riscv                    nommu_k210_defconfig
riscv                            allyesconfig
riscv                             allnoconfig
riscv                               defconfig
x86_64                                   rhel
x86_64                           allyesconfig
x86_64                    rhel-7.6-kselftests
x86_64                              defconfig
x86_64                               rhel-8.3
x86_64                      rhel-8.3-kbuiltin
x86_64                                  kexec

clang tested configs:
x86_64               randconfig-a013-20210108
x86_64               randconfig-a011-20210108
x86_64               randconfig-a012-20210108
x86_64               randconfig-a016-20210108
x86_64               randconfig-a014-20210108
x86_64               randconfig-a015-20210108

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all at lists.01.org


From hch at lst.de  Sat Jan  9 05:42:48 2021
From: hch at lst.de (Christoph Hellwig)
Date: Sat,  9 Jan 2021 11:42:48 +0100
Subject: split hard read-only vs read-only policy v3 (resend)
Message-ID: <20210109104254.1077093-1-hch@lst.de>

Hi Jens,

this series resurrects a patch from Martin to properly split the flag
indicating a disk has been set read-only by the hardware vs the userspace
policy set through the BLKROSET ioctl.

Note that the last patch only applies to for-next and not to
for-5.11/block.  I can hold it back for the first NVMe pull request after
Linus pulled the block tree.

A git tree is available here:

    git://git.infradead.org/users/hch/block.git block-hard-ro

Gitweb:

    http://git.infradead.org/users/hch/block.git/shortlog/refs/heads/block-hard-ro

Changes since v3:
 - rebased to the latest block tree
 - indent commit log lines starting with a "#" to make sure git commit
   doesn't eat them

Changes since v2:
 - fix a few typos
 - add a patch to propagate the read-only status from the whole device to
   partitions
 - add a patch to remove a pointless check from bdev_read_only

Changes since v1:
 - don't propagate the policy flag from the whole disk to partitions
 - rebased on top of the merge block_device and hd_struct series


From hch at lst.de  Sat Jan  9 05:42:49 2021
From: hch at lst.de (Christoph Hellwig)
Date: Sat,  9 Jan 2021 11:42:49 +0100
Subject: [PATCH 1/6] dm: use bdev_read_only to check if a device is read-only
In-Reply-To: <20210109104254.1077093-1-hch@lst.de>
References: <20210109104254.1077093-1-hch@lst.de>
Message-ID: <20210109104254.1077093-2-hch@lst.de>

dm-thin and dm-cache also work on partitions, so use the proper
interface to check if the device is read-only.

Signed-off-by: Christoph Hellwig <hch at lst.de>
Reviewed-by: Ming Lei <ming.lei at redhat.com>
Reviewed-by: Martin K. Petersen <martin.petersen at oracle.com>
Reviewed-by: Hannes Reinecke <hare at suse.de>
---
 drivers/md/dm-cache-metadata.c | 2 +-
 drivers/md/dm-thin-metadata.c  | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c
index af6d4f898e4c1d..89a73204dbf47f 100644
--- a/drivers/md/dm-cache-metadata.c
+++ b/drivers/md/dm-cache-metadata.c
@@ -449,7 +449,7 @@ static int __check_incompat_features(struct cache_disk_superblock *disk_super,
 	/*
 	 * Check for read-only metadata to skip the following RDWR checks.
 	 */
-	if (get_disk_ro(cmd->bdev->bd_disk))
+	if (bdev_read_only(cmd->bdev))
 		return 0;
 
 	features = le32_to_cpu(disk_super->compat_ro_flags) & ~DM_CACHE_FEATURE_COMPAT_RO_SUPP;
diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c
index 6ebb2127f3e2e0..e75b20480e460e 100644
--- a/drivers/md/dm-thin-metadata.c
+++ b/drivers/md/dm-thin-metadata.c
@@ -636,7 +636,7 @@ static int __check_incompat_features(struct thin_disk_superblock *disk_super,
 	/*
 	 * Check for read-only metadata to skip the following RDWR checks.
 	 */
-	if (get_disk_ro(pmd->bdev->bd_disk))
+	if (bdev_read_only(pmd->bdev))
 		return 0;
 
 	features = le32_to_cpu(disk_super->compat_ro_flags) & ~THIN_FEATURE_COMPAT_RO_SUPP;
-- 
2.29.2



From hch at lst.de  Sat Jan  9 05:42:50 2021
From: hch at lst.de (Christoph Hellwig)
Date: Sat,  9 Jan 2021 11:42:50 +0100
Subject: [PATCH 2/6] block: remove the NULL bdev check in bdev_read_only
In-Reply-To: <20210109104254.1077093-1-hch@lst.de>
References: <20210109104254.1077093-1-hch@lst.de>
Message-ID: <20210109104254.1077093-3-hch@lst.de>

Only a single caller can end up in bdev_read_only, so move the check
there.

Signed-off-by: Christoph Hellwig <hch at lst.de>
Reviewed-by: Ming Lei <ming.lei at redhat.com>
Reviewed-by: Martin K. Petersen <martin.petersen at oracle.com>
---
 block/genhd.c | 3 ---
 fs/super.c    | 3 ++-
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/block/genhd.c b/block/genhd.c
index 73faec438e49a8..4f90f80d7aa76d 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -1654,11 +1654,8 @@ EXPORT_SYMBOL(set_disk_ro);
 
 int bdev_read_only(struct block_device *bdev)
 {
-	if (!bdev)
-		return 0;
 	return bdev->bd_read_only;
 }
-
 EXPORT_SYMBOL(bdev_read_only);
 
 /*
diff --git a/fs/super.c b/fs/super.c
index 2c6cdea2ab2d9e..5a1f384ffc74f6 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -865,7 +865,8 @@ int reconfigure_super(struct fs_context *fc)
 
 	if (fc->sb_flags_mask & SB_RDONLY) {
 #ifdef CONFIG_BLOCK
-		if (!(fc->sb_flags & SB_RDONLY) && bdev_read_only(sb->s_bdev))
+		if (!(fc->sb_flags & SB_RDONLY) && sb->s_bdev &&
+		    bdev_read_only(sb->s_bdev))
 			return -EACCES;
 #endif
 
-- 
2.29.2



From hch at lst.de  Sat Jan  9 05:42:51 2021
From: hch at lst.de (Christoph Hellwig)
Date: Sat,  9 Jan 2021 11:42:51 +0100
Subject: [PATCH 3/6] block: add a hard-readonly flag to struct gendisk
In-Reply-To: <20210109104254.1077093-1-hch@lst.de>
References: <20210109104254.1077093-1-hch@lst.de>
Message-ID: <20210109104254.1077093-4-hch@lst.de>

Commit 20bd1d026aac ("scsi: sd: Keep disk read-only when re-reading
partition") addressed a long-standing problem with user read-only
policy being overridden as a result of a device-initiated revalidate.
The commit has since been reverted due to a regression that left some
USB devices read-only indefinitely.

To fix the underlying problems with revalidate we need to keep track
of hardware state and user policy separately.

The gendisk has been updated to reflect the current hardware state set
by the device driver. This is done to allow returning the device to
the hardware state once the user clears the BLKROSET flag.

The resulting semantics are as follows:

 - If BLKROSET sets a given partition read-only, that partition will
   remain read-only even if the underlying storage stack initiates a
   revalidate. However, the BLKRRPART ioctl will cause the partition
   table to be dropped and any user policy on partitions will be lost.

 - If BLKROSET has not been set, both the whole disk device and any
   partitions will reflect the current write-protect state of the
   underlying device.

Based on a patch from Martin K. Petersen <martin.petersen at oracle.com>.

Reported-by: Oleksii Kurochko <olkuroch at cisco.com>
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=201221
Signed-off-by: Christoph Hellwig <hch at lst.de>
Reviewed-by: Ming Lei <ming.lei at redhat.com>
Reviewed-by: Martin K. Petersen <martin.petersen at oracle.com>
Reviewed-by: Hannes Reinecke <hare at suse.de>
---
 block/blk-core.c        |  4 +---
 block/genhd.c           | 33 +++++++++++++++++++--------------
 block/partitions/core.c |  3 +--
 include/linux/genhd.h   |  6 ++++--
 4 files changed, 25 insertions(+), 21 deletions(-)

diff --git a/block/blk-core.c b/block/blk-core.c
index 7663a9b94b8002..08ff8ca325296e 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -694,9 +694,7 @@ static inline bool should_fail_request(struct block_device *part,
 
 static inline bool bio_check_ro(struct bio *bio, struct block_device *part)
 {
-	const int op = bio_op(bio);
-
-	if (part->bd_read_only && op_is_write(op)) {
+	if (op_is_write(bio_op(bio)) && bdev_read_only(part)) {
 		char b[BDEVNAME_SIZE];
 
 		if (op_is_flush(bio->bi_opf) && !bio_sectors(bio))
diff --git a/block/genhd.c b/block/genhd.c
index 4f90f80d7aa76d..e70bdc9b0893c1 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -1634,27 +1634,32 @@ static void set_disk_ro_uevent(struct gendisk *gd, int ro)
 	kobject_uevent_env(&disk_to_dev(gd)->kobj, KOBJ_CHANGE, envp);
 }
 
-void set_disk_ro(struct gendisk *disk, int flag)
+/**
+ * set_disk_ro - set a gendisk read-only
+ * @disk:	gendisk to operate on
+ * @ready_only:	%true to set the disk read-only, %false set the disk read/write
+ *
+ * This function is used to indicate whether a given disk device should have its
+ * read-only flag set. set_disk_ro() is typically used by device drivers to
+ * indicate whether the underlying physical device is write-protected.
+ */
+void set_disk_ro(struct gendisk *disk, bool read_only)
 {
-	struct disk_part_iter piter;
-	struct block_device *part;
-
-	if (disk->part0->bd_read_only != flag) {
-		set_disk_ro_uevent(disk, flag);
-		disk->part0->bd_read_only = flag;
+	if (read_only) {
+		if (test_and_set_bit(GD_READ_ONLY, &disk->state))
+			return;
+	} else {
+		if (!test_and_clear_bit(GD_READ_ONLY, &disk->state))
+			return;
 	}
-
-	disk_part_iter_init(&piter, disk, DISK_PITER_INCL_EMPTY);
-	while ((part = disk_part_iter_next(&piter)))
-		part->bd_read_only = flag;
-	disk_part_iter_exit(&piter);
+	set_disk_ro_uevent(disk, read_only);
 }
-
 EXPORT_SYMBOL(set_disk_ro);
 
 int bdev_read_only(struct block_device *bdev)
 {
-	return bdev->bd_read_only;
+	return bdev->bd_read_only ||
+		test_bit(GD_READ_ONLY, &bdev->bd_disk->state);
 }
 EXPORT_SYMBOL(bdev_read_only);
 
diff --git a/block/partitions/core.c b/block/partitions/core.c
index e7d776db803b12..168d5906077cfd 100644
--- a/block/partitions/core.c
+++ b/block/partitions/core.c
@@ -195,7 +195,7 @@ static ssize_t part_start_show(struct device *dev,
 static ssize_t part_ro_show(struct device *dev,
 			    struct device_attribute *attr, char *buf)
 {
-	return sprintf(buf, "%d\n", dev_to_bdev(dev)->bd_read_only);
+	return sprintf(buf, "%d\n", bdev_read_only(dev_to_bdev(dev)));
 }
 
 static ssize_t part_alignment_offset_show(struct device *dev,
@@ -361,7 +361,6 @@ static struct block_device *add_partition(struct gendisk *disk, int partno,
 
 	bdev->bd_start_sect = start;
 	bdev_set_nr_sectors(bdev, len);
-	bdev->bd_read_only = get_disk_ro(disk);
 
 	if (info) {
 		err = -ENOMEM;
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 809aaa32d53cba..a62ccbfac54b48 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -163,6 +163,7 @@ struct gendisk {
 	int flags;
 	unsigned long state;
 #define GD_NEED_PART_SCAN		0
+#define GD_READ_ONLY			1
 	struct kobject *slave_dir;
 
 	struct timer_rand_state *random;
@@ -249,11 +250,12 @@ static inline void add_disk_no_queue_reg(struct gendisk *disk)
 extern void del_gendisk(struct gendisk *gp);
 extern struct block_device *bdget_disk(struct gendisk *disk, int partno);
 
-extern void set_disk_ro(struct gendisk *disk, int flag);
+void set_disk_ro(struct gendisk *disk, bool read_only);
 
 static inline int get_disk_ro(struct gendisk *disk)
 {
-	return disk->part0->bd_read_only;
+	return disk->part0->bd_read_only ||
+		test_bit(GD_READ_ONLY, &disk->state);
 }
 
 extern void disk_block_events(struct gendisk *disk);
-- 
2.29.2



From hch at lst.de  Sat Jan  9 05:42:52 2021
From: hch at lst.de (Christoph Hellwig)
Date: Sat,  9 Jan 2021 11:42:52 +0100
Subject: [PATCH 4/6] block: propagate BLKROSET on the whole device to all
 partitions
In-Reply-To: <20210109104254.1077093-1-hch@lst.de>
References: <20210109104254.1077093-1-hch@lst.de>
Message-ID: <20210109104254.1077093-5-hch@lst.de>

Change the policy so that a BLKROSET on the whole device also affects
partitions.  To quote Martin K. Petersen:

It's very common for database folks to twiddle the read-only state of
block devices and partitions. I know that our users will find it very
counter-intuitive that setting /dev/sda read-only won't prevent writes
to /dev/sda1.

The existing behavior is inconsistent in the sense that doing:

  # blockdev --setro /dev/sda
  # echo foo > /dev/sda1

permits writes. But:

  # blockdev --setro /dev/sda
  <something triggers revalidate>
  # echo foo > /dev/sda1

doesn't.

And a subsequent:

  # blockdev --setrw /dev/sda
  # echo foo > /dev/sda1

doesn't work either since sda1's read-only policy has been inherited
from the whole-disk device.

You need to do:

  # blockdev --rereadpt

after setting the whole-disk device rw to effectuate the same change on
the partitions, otherwise they are stuck being read-only indefinitely.

However, setting the read-only policy on a partition does *not* require
the revalidate step. As a matter of fact, doing the revalidate will blow
away the policy setting you just made.

So the user needs to take different actions depending on whether they
are trying to read-protect a whole-disk device or a partition. Despite
using the same ioctl. That is really confusing.

I have lost count how many times our customers have had data clobbered
because of ambiguity of the existing whole-disk device policy. The
current behavior violates the principle of least surprise by letting the
user think they write protected the whole disk when they actually
didn't.

Suggested-by: Martin K. Petersen <martin.petersen at oracle.com>
Signed-off-by: Christoph Hellwig <hch at lst.de>
Reviewed-by: Martin K. Petersen <martin.petersen at oracle.com>
---
 block/genhd.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/block/genhd.c b/block/genhd.c
index e70bdc9b0893c1..10c76320510fef 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -1658,8 +1658,7 @@ EXPORT_SYMBOL(set_disk_ro);
 
 int bdev_read_only(struct block_device *bdev)
 {
-	return bdev->bd_read_only ||
-		test_bit(GD_READ_ONLY, &bdev->bd_disk->state);
+	return bdev->bd_read_only || get_disk_ro(bdev->bd_disk);
 }
 EXPORT_SYMBOL(bdev_read_only);
 
-- 
2.29.2



From hch at lst.de  Sat Jan  9 05:42:53 2021
From: hch at lst.de (Christoph Hellwig)
Date: Sat,  9 Jan 2021 11:42:53 +0100
Subject: [PATCH 5/6] rbd: remove the ->set_read_only method
In-Reply-To: <20210109104254.1077093-1-hch@lst.de>
References: <20210109104254.1077093-1-hch@lst.de>
Message-ID: <20210109104254.1077093-6-hch@lst.de>

Now that the hardware read-only state can't be changed by the BLKROSET
ioctl, the code in this method is not required anymore.

Signed-off-by: Christoph Hellwig <hch at lst.de>
Reviewed-by: Hannes Reinecke <hare at suse.de>
Acked-by: Ilya Dryomov <idryomov at gmail.com>
Reviewed-by: Martin K. Petersen <martin.petersen at oracle.com>
---
 drivers/block/rbd.c | 19 -------------------
 1 file changed, 19 deletions(-)

diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index 59cfe71d0b3a39..bbb88eb009e0ba 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -692,29 +692,10 @@ static void rbd_release(struct gendisk *disk, fmode_t mode)
 	put_device(&rbd_dev->dev);
 }
 
-static int rbd_set_read_only(struct block_device *bdev, bool ro)
-{
-	struct rbd_device *rbd_dev = bdev->bd_disk->private_data;
-
-	/*
-	 * Both images mapped read-only and snapshots can't be marked
-	 * read-write.
-	 */
-	if (!ro) {
-		if (rbd_is_ro(rbd_dev))
-			return -EROFS;
-
-		rbd_assert(!rbd_is_snap(rbd_dev));
-	}
-
-	return 0;
-}
-
 static const struct block_device_operations rbd_bd_ops = {
 	.owner			= THIS_MODULE,
 	.open			= rbd_open,
 	.release		= rbd_release,
-	.set_read_only		= rbd_set_read_only,
 };
 
 /*
-- 
2.29.2



From hch at lst.de  Sat Jan  9 05:42:54 2021
From: hch at lst.de (Christoph Hellwig)
Date: Sat,  9 Jan 2021 11:42:54 +0100
Subject: [PATCH 6/6] nvme: allow revalidate to set a namespace read-only
In-Reply-To: <20210109104254.1077093-1-hch@lst.de>
References: <20210109104254.1077093-1-hch@lst.de>
Message-ID: <20210109104254.1077093-7-hch@lst.de>

Unconditionally call set_disk_ro now that it only updates the hardware
state.  This allows to properly set up the Linux devices read-only when
the controller turns a previously writable namespace read-only.

Signed-off-by: Christoph Hellwig <hch at lst.de>
Reviewed-by: Keith Busch <kbusch at kernel.org>
Reviewed-by: Martin K. Petersen <martin.petersen at oracle.com>
---
 drivers/nvme/host/core.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index ce1b6151944131..3a0557ccc9fc5d 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -2114,9 +2114,8 @@ static void nvme_update_disk_info(struct gendisk *disk,
 	nvme_config_discard(disk, ns);
 	nvme_config_write_zeroes(disk, ns);
 
-	if ((id->nsattr & NVME_NS_ATTR_RO) ||
-	    test_bit(NVME_NS_FORCE_RO, &ns->flags))
-		set_disk_ro(disk, true);
+	set_disk_ro(disk, (id->nsattr & NVME_NS_ATTR_RO) ||
+		test_bit(NVME_NS_FORCE_RO, &ns->flags));
 }
 
 static inline bool nvme_first_scan(struct gendisk *disk)
-- 
2.29.2



From Chaitanya.Kulkarni at wdc.com  Sat Jan  9 15:14:09 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Sat, 9 Jan 2021 20:14:09 +0000
Subject: [PATCH 2/6] block: remove the NULL bdev check in bdev_read_only
References: <20210109104254.1077093-1-hch@lst.de>
 <20210109104254.1077093-3-hch@lst.de>
Message-ID: <BYAPR04MB4965B6AC1FAAC270F636F7BE86AD0@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/9/21 02:48, Christoph Hellwig wrote:
> Only a single caller can end up in bdev_read_only, so move the check
> there.
>
> Signed-off-by: Christoph Hellwig <hch at lst.de>
> Reviewed-by: Ming Lei <ming.lei at redhat.com>
> Reviewed-by: Martin K. Petersen <martin.petersen at oracle.com>
Looks good.

Reviewed-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>



From Chaitanya.Kulkarni at wdc.com  Sat Jan  9 15:27:26 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Sat, 9 Jan 2021 20:27:26 +0000
Subject: [PATCH 6/6] nvme: allow revalidate to set a namespace read-only
References: <20210109104254.1077093-1-hch@lst.de>
 <20210109104254.1077093-7-hch@lst.de>
Message-ID: <BYAPR04MB4965CD87B0E6CBA2FFD0B09886AD0@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/9/21 02:49, Christoph Hellwig wrote:
> Unconditionally call set_disk_ro now that it only updates the hardware
> state.  This allows to properly set up the Linux devices read-only when
> the controller turns a previously writable namespace read-only.
>
> Signed-off-by: Christoph Hellwig <hch at lst.de>
> Reviewed-by: Keith Busch <kbusch at kernel.org>
> Reviewed-by: Martin K. Petersen <martin.petersen at oracle.com>
> ---
>  drivers/nvme/host/core.c | 5 ++---
>  1 file changed, 2 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
> index ce1b6151944131..3a0557ccc9fc5d 100644
> --- a/drivers/nvme/host/core.c
> +++ b/drivers/nvme/host/core.c
> @@ -2114,9 +2114,8 @@ static void nvme_update_disk_info(struct gendisk *disk,
>  	nvme_config_discard(disk, ns);
>  	nvme_config_write_zeroes(disk, ns);
>  
> -	if ((id->nsattr & NVME_NS_ATTR_RO) ||
> -	    test_bit(NVME_NS_FORCE_RO, &ns->flags))
> -		set_disk_ro(disk, true);
> +	set_disk_ro(disk, (id->nsattr & NVME_NS_ATTR_RO) ||
> +		test_bit(NVME_NS_FORCE_RO, &ns->flags));
>  }
>  

If we are adding a multi-line function call can we please consider
following, on the top of this that matches earlier multi-line function
call in the same nvme_update_disk_into() :-

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 3a0557ccc9fc..5cf0f801a95e 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -2115,7 +2115,7 @@ static void nvme_update_disk_info(struct gendisk
*disk,
        nvme_config_write_zeroes(disk, ns);
 
        set_disk_ro(disk, (id->nsattr & NVME_NS_ATTR_RO) ||
-               test_bit(NVME_NS_FORCE_RO, &ns->flags));
+                   test_bit(NVME_NS_FORCE_RO, &ns->flags));
 }
 
static inline bool nvme_first_scan(struct gendisk *disk)

Otherwise, looks good.
Reviewed-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
>  static inline bool nvme_first_scan(struct gendisk *disk)



From Chaitanya.Kulkarni at wdc.com  Sat Jan  9 15:34:11 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Sat, 9 Jan 2021 20:34:11 +0000
Subject: [PATCH 1/3] nvme: support command retry delay for admin command
References: <20210108144659.7126-1-minwoo.im.dev@gmail.com>
 <20210108144659.7126-2-minwoo.im.dev@gmail.com>
Message-ID: <BYAPR04MB4965078A7B0C75B03D342EFD86AD0@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/8/21 06:54, Minwoo Im wrote:
> This feature can be applied not only I/O queue commands, but also admin
> queue commands.  Admin command during the initialization may fail due to
> some un-ready state of a controller, so it would be better to have this
> feature for admin commands also.
What is some un-ready state ?


From minwoo.im.dev at gmail.com  Sat Jan  9 20:33:16 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Sun, 10 Jan 2021 10:33:16 +0900
Subject: [PATCH 1/3] nvme: support command retry delay for admin command
In-Reply-To: <BYAPR04MB4965078A7B0C75B03D342EFD86AD0@BYAPR04MB4965.namprd04.prod.outlook.com>
References: <20210108144659.7126-1-minwoo.im.dev@gmail.com>
 <20210108144659.7126-2-minwoo.im.dev@gmail.com>
 <BYAPR04MB4965078A7B0C75B03D342EFD86AD0@BYAPR04MB4965.namprd04.prod.outlook.com>
Message-ID: <20210110013316.GA4369@localhost.localdomain>

Hello,

On 21-01-09 20:34:11, Chaitanya Kulkarni wrote:
> On 1/8/21 06:54, Minwoo Im wrote:
> > This feature can be applied not only I/O queue commands, but also admin
> > queue commands.  Admin command during the initialization may fail due to
> > some un-ready state of a controller, so it would be better to have this
> > feature for admin commands also.
> What is some un-ready state ?

State that controller is unable to process successfully command as
"Command Interrupt" status code represents.

Thanks,


From gerlitz.or at gmail.com  Sun Jan 10 03:06:51 2021
From: gerlitz.or at gmail.com (Or Gerlitz)
Date: Sun, 10 Jan 2021 10:06:51 +0200
Subject: [PATCH] nvme-tcp: Fix possible race of io_work and direct send
In-Reply-To: <e206eb55-8792-b9c2-64cb-bd76ed09e12e@grimberg.me>
References: <20201221080339.945164-1-sagi@grimberg.me>
 <CAJ3xEMj8Y_=Y=orV59GR9=L4M3r4+mZzMW6w2cv2K9d5eKXZDA@mail.gmail.com>
 <e206eb55-8792-b9c2-64cb-bd76ed09e12e@grimberg.me>
Message-ID: <CAJ3xEMj_GYOQA3hisdAPw3ybR55Un24+_9M51kvwiAkqvUOojg@mail.gmail.com>

On Fri, Jan 8, 2021 at 10:20 PM Sagi Grimberg <sagi at grimberg.me> wrote:

> Well, this is a heuristic anyways, too bad we need to
> disable preemption just for this...
>
> I'm assuming that this makes the issue go away?
> --
> diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
> index cf856103025a..ea07336ca179 100644
> --- a/drivers/nvme/host/tcp.c
> +++ b/drivers/nvme/host/tcp.c
> @@ -281,8 +281,11 @@ static inline void nvme_tcp_queue_request(struct
> nvme_tcp_request *req,
>                  bool sync, bool last)
>   {
>          struct nvme_tcp_queue *queue = req->queue;
> +       int cpu;
>          bool empty;
>
> +       cpu = get_cpu();
> +       put_cpu();
>          empty = llist_add(&req->lentry, &queue->req_list) &&
>                  list_empty(&queue->send_list) && !queue->request;
>
> @@ -291,8 +294,8 @@ static inline void nvme_tcp_queue_request(struct
> nvme_tcp_request *req,
>           * directly, otherwise queue io_work. Also, only do that if we
>           * are on the same cpu, so we don't introduce contention.
>           */
> -       if (queue->io_cpu == smp_processor_id() &&
> -           sync && empty && mutex_trylock(&queue->send_mutex)) {
> +       if (queue->io_cpu == cpu && sync && empty &&


if preemption happens here, the value returned by get_cpu() is not where
we run when the actual comparison takes place. So what you are saying
is that overall correctness will not be hurt? worth putting a comment
here for readers / future modifiers of the code

> +           mutex_trylock(&queue->send_mutex)) {
>                  queue->more_requests = !last;
>                  nvme_tcp_send_all(queue);
>                  queue->more_requests = false;


From israelr at nvidia.com  Sun Jan 10 07:09:05 2021
From: israelr at nvidia.com (Israel Rukshin)
Date: Sun, 10 Jan 2021 14:09:05 +0200
Subject: [PATCH] nvmet-rdma: Fix NULL deref when setting pi_enable and traddr
 INADDR_ANY
Message-ID: <1610280545-57812-1-git-send-email-israelr@nvidia.com>

When setting port traddr to INADDR_ANY, the listening cm_id->device
is NULL. The associate IB device is known only when a connect request
event arrives, so checking T10-PI device capability should be done
at this stage.

Fixes: b09160c3996c ("nvmet-rdma: add metadata/T10-PI support")
Signed-off-by: Israel Rukshin <israelr at nvidia.com>
Reviewed-by: Max Gurtovoy <mgurtovoy at nvidia.com>
---
 drivers/nvme/target/rdma.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c
index bdfc22eb2a10..06b6b742bb21 100644
--- a/drivers/nvme/target/rdma.c
+++ b/drivers/nvme/target/rdma.c
@@ -1220,6 +1220,14 @@ nvmet_rdma_find_get_device(struct rdma_cm_id *cm_id)
 	}
 	ndev->inline_data_size = nport->inline_data_size;
 	ndev->inline_page_count = inline_page_count;
+
+	if (nport->pi_enable && !(cm_id->device->attrs.device_cap_flags &
+				  IB_DEVICE_INTEGRITY_HANDOVER)) {
+		pr_warn("T10-PI is not supported by device %s. Disabling it\n",
+			cm_id->device->name);
+		nport->pi_enable = false;
+	}
+
 	ndev->device = cm_id->device;
 	kref_init(&ndev->ref);
 
@@ -1855,14 +1863,6 @@ static int nvmet_rdma_enable_port(struct nvmet_rdma_port *port)
 		goto out_destroy_id;
 	}
 
-	if (port->nport->pi_enable &&
-	    !(cm_id->device->attrs.device_cap_flags &
-	      IB_DEVICE_INTEGRITY_HANDOVER)) {
-		pr_err("T10-PI is not supported for %pISpcs\n", addr);
-		ret = -EINVAL;
-		goto out_destroy_id;
-	}
-
 	port->cm_id = cm_id;
 	return 0;
 
-- 
2.18.2



From hare at suse.de  Sun Jan 10 09:59:42 2021
From: hare at suse.de (Hannes Reinecke)
Date: Sun, 10 Jan 2021 15:59:42 +0100
Subject: [PATCH 2/6] block: remove the NULL bdev check in bdev_read_only
In-Reply-To: <20210109104254.1077093-3-hch@lst.de>
References: <20210109104254.1077093-1-hch@lst.de>
 <20210109104254.1077093-3-hch@lst.de>
Message-ID: <9ed48321-4fa9-84a6-ac39-9b4ca56e81e6@suse.de>

On 1/9/21 11:42 AM, Christoph Hellwig wrote:
> Only a single caller can end up in bdev_read_only, so move the check
> there.
> 
> Signed-off-by: Christoph Hellwig <hch at lst.de>
> Reviewed-by: Ming Lei <ming.lei at redhat.com>
> Reviewed-by: Martin K. Petersen <martin.petersen at oracle.com>
> ---
>   block/genhd.c | 3 ---
>   fs/super.c    | 3 ++-
>   2 files changed, 2 insertions(+), 4 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare at suse.de>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare at suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 N?rnberg
HRB 36809 (AG N?rnberg), Gesch?ftsf?hrer: Felix Imend?rffer


From hare at suse.de  Sun Jan 10 10:00:48 2021
From: hare at suse.de (Hannes Reinecke)
Date: Sun, 10 Jan 2021 16:00:48 +0100
Subject: [PATCH 4/6] block: propagate BLKROSET on the whole device to all
 partitions
In-Reply-To: <20210109104254.1077093-5-hch@lst.de>
References: <20210109104254.1077093-1-hch@lst.de>
 <20210109104254.1077093-5-hch@lst.de>
Message-ID: <81a37585-bf6e-9ab5-993e-e9a0881ce996@suse.de>

On 1/9/21 11:42 AM, Christoph Hellwig wrote:
> Change the policy so that a BLKROSET on the whole device also affects
> partitions.  To quote Martin K. Petersen:
> 
> It's very common for database folks to twiddle the read-only state of
> block devices and partitions. I know that our users will find it very
> counter-intuitive that setting /dev/sda read-only won't prevent writes
> to /dev/sda1.
> 
> The existing behavior is inconsistent in the sense that doing:
> 
>    # blockdev --setro /dev/sda
>    # echo foo > /dev/sda1
> 
> permits writes. But:
> 
>    # blockdev --setro /dev/sda
>    <something triggers revalidate>
>    # echo foo > /dev/sda1
> 
> doesn't.
> 
> And a subsequent:
> 
>    # blockdev --setrw /dev/sda
>    # echo foo > /dev/sda1
> 
> doesn't work either since sda1's read-only policy has been inherited
> from the whole-disk device.
> 
> You need to do:
> 
>    # blockdev --rereadpt
> 
> after setting the whole-disk device rw to effectuate the same change on
> the partitions, otherwise they are stuck being read-only indefinitely.
> 
> However, setting the read-only policy on a partition does *not* require
> the revalidate step. As a matter of fact, doing the revalidate will blow
> away the policy setting you just made.
> 
> So the user needs to take different actions depending on whether they
> are trying to read-protect a whole-disk device or a partition. Despite
> using the same ioctl. That is really confusing.
> 
> I have lost count how many times our customers have had data clobbered
> because of ambiguity of the existing whole-disk device policy. The
> current behavior violates the principle of least surprise by letting the
> user think they write protected the whole disk when they actually
> didn't.
> 
> Suggested-by: Martin K. Petersen <martin.petersen at oracle.com>
> Signed-off-by: Christoph Hellwig <hch at lst.de>
> Reviewed-by: Martin K. Petersen <martin.petersen at oracle.com>
> ---
>   block/genhd.c | 3 +--
>   1 file changed, 1 insertion(+), 2 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare at suse.de>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare at suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 N?rnberg
HRB 36809 (AG N?rnberg), Gesch?ftsf?hrer: Felix Imend?rffer


From hare at suse.de  Sun Jan 10 10:01:17 2021
From: hare at suse.de (Hannes Reinecke)
Date: Sun, 10 Jan 2021 16:01:17 +0100
Subject: [PATCH 6/6] nvme: allow revalidate to set a namespace read-only
In-Reply-To: <20210109104254.1077093-7-hch@lst.de>
References: <20210109104254.1077093-1-hch@lst.de>
 <20210109104254.1077093-7-hch@lst.de>
Message-ID: <3269f70a-2bd4-9aa6-5f14-b13e5b67687e@suse.de>

On 1/9/21 11:42 AM, Christoph Hellwig wrote:
> Unconditionally call set_disk_ro now that it only updates the hardware
> state.  This allows to properly set up the Linux devices read-only when
> the controller turns a previously writable namespace read-only.
> 
> Signed-off-by: Christoph Hellwig <hch at lst.de>
> Reviewed-by: Keith Busch <kbusch at kernel.org>
> Reviewed-by: Martin K. Petersen <martin.petersen at oracle.com>
> ---
>   drivers/nvme/host/core.c | 5 ++---
>   1 file changed, 2 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
> index ce1b6151944131..3a0557ccc9fc5d 100644
> --- a/drivers/nvme/host/core.c
> +++ b/drivers/nvme/host/core.c
> @@ -2114,9 +2114,8 @@ static void nvme_update_disk_info(struct gendisk *disk,
>   	nvme_config_discard(disk, ns);
>   	nvme_config_write_zeroes(disk, ns);
>   
> -	if ((id->nsattr & NVME_NS_ATTR_RO) ||
> -	    test_bit(NVME_NS_FORCE_RO, &ns->flags))
> -		set_disk_ro(disk, true);
> +	set_disk_ro(disk, (id->nsattr & NVME_NS_ATTR_RO) ||
> +		test_bit(NVME_NS_FORCE_RO, &ns->flags));
>   }
>   
>   static inline bool nvme_first_scan(struct gendisk *disk)
> 
Reviewed-by: Hannes Reinecke <hare at suse.de>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare at suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 N?rnberg
HRB 36809 (AG N?rnberg), Gesch?ftsf?hrer: Felix Imend?rffer


From lengchao at huawei.com  Sun Jan 10 22:47:56 2021
From: lengchao at huawei.com (Chao Leng)
Date: Mon, 11 Jan 2021 11:47:56 +0800
Subject: [PATCH 3/3] nvme: add parameter command_retry to enable retry
In-Reply-To: <20210108144659.7126-4-minwoo.im.dev@gmail.com>
References: <20210108144659.7126-1-minwoo.im.dev@gmail.com>
 <20210108144659.7126-4-minwoo.im.dev@gmail.com>
Message-ID: <dfe59030-3eab-a178-7264-792f76dffe4c@huawei.com>



On 2021/1/8 22:46, Minwoo Im wrote:
> nvme_init_request() has set REQ_FAILFAST_DRIVER to make requests
> non-retryable.  This command flag value is checked in
> nvme_decide_disposition() to decide whether to RETRY or other
> operations.  In that point, blk_noretry_request() macro will be used to
> check if command flags have one of REQ_FAILFAST_*.  If so, it just
> decides to complete the request without retrying.
> 
> This patch added a module parameter named command_retry to turn on the
> command retry feature in this driver.  If turning it on,
> REQ3_FAILFAST_DRIVER will not be set to requests so that retry can be
> reached out to nvme_retry_req() based on the module parameter.
> 
> Signed-off-by: Minwoo Im <minwoo.im.dev at gmail.com>
> ---
>   drivers/nvme/host/core.c | 7 ++++++-
>   1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
> index 6e428fdc25a8..e1836ca9956f 100644
> --- a/drivers/nvme/host/core.c
> +++ b/drivers/nvme/host/core.c
> @@ -44,6 +44,10 @@ static unsigned char shutdown_timeout = 5;
>   module_param(shutdown_timeout, byte, 0644);
>   MODULE_PARM_DESC(shutdown_timeout, "timeout in seconds for controller shutdown");
>   
> +static bool command_retry;
> +module_param(command_retry, bool, 0644);
> +MODULE_PARM_DESC(command_retry, "retry commands up to nvme_max_retries");
> +
>   static u8 nvme_max_retries = 5;
>   module_param_named(max_retries, nvme_max_retries, byte, 0644);
>   MODULE_PARM_DESC(max_retries, "max number of retries a command may have");
> @@ -560,7 +564,8 @@ static inline void nvme_init_request(struct request *req,
>   	else /* no queuedata implies admin queue */
>   		req->timeout = NVME_ADMIN_TIMEOUT;
>   
> -	req->cmd_flags |= REQ_FAILFAST_DRIVER;
> +	if (!command_retry)
> +		req->cmd_flags |= REQ_FAILFAST_DRIVER;
In abnormal scenarios, such as request time out, connection process may takes long time or the admin command waits for long time.
Retry only for non-host errors may be a better choice. Maybe we can make some optimizations in nvme_decide_disposition.
>   	nvme_clear_nvme_request(req);
>   	nvme_req(req)->cmd = cmd;
>   }
> 


From hare at suse.de  Mon Jan 11 02:29:17 2021
From: hare at suse.de (Hannes Reinecke)
Date: Mon, 11 Jan 2021 08:29:17 +0100
Subject: [PATCH v7 01/16] cgroup: Added cgroup_get_from_id
In-Reply-To: <1609970430-19084-2-git-send-email-muneendra.kumar@broadcom.com>
References: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
 <1609970430-19084-2-git-send-email-muneendra.kumar@broadcom.com>
Message-ID: <0a1453c2-9f8a-0818-1678-78e1775a773b@suse.de>

On 1/6/21 11:00 PM, Muneendra wrote:
> Added a new function cgroup_get_from_id  to retrieve the cgroup
> associated with cgroup id.
> Exported the same as this can be used by blk-cgorup.c
> 
> Added function declaration of cgroup_get_from_id in cgorup.h
> 
> This patch also exported the function cgroup_get_e_css
> as this is getting used in blk-cgroup.h
> 
> Signed-off-by: Muneendra <muneendra.kumar at broadcom.com>
> 
> ---
> v7:
> No change
> 
> v6:
> No change
> 
> v5:
> renamed the function cgroup_get_from_kernfs_id to
> cgroup_get_from_id
> 
> v4:
> No change
> 
> v3:
> Exported the cgroup_get_e_css
> 
> v2:
> New patch
> ---
>   include/linux/cgroup.h |  6 ++++++
>   kernel/cgroup/cgroup.c | 26 ++++++++++++++++++++++++++
>   2 files changed, 32 insertions(+)
> 
Reviewed-by: Hannes Reinecke <hare at suse.de>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare at suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 N?rnberg
HRB 36809 (AG N?rnberg), Gesch?ftsf?hrer: Felix Imend?rffer


From hare at suse.de  Mon Jan 11 02:30:21 2021
From: hare at suse.de (Hannes Reinecke)
Date: Mon, 11 Jan 2021 08:30:21 +0100
Subject: [PATCH v7 02/16] blkcg: Added a app identifier support for blkcg
In-Reply-To: <1609970430-19084-3-git-send-email-muneendra.kumar@broadcom.com>
References: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
 <1609970430-19084-3-git-send-email-muneendra.kumar@broadcom.com>
Message-ID: <d2f7a39d-203a-c542-3d50-997acaded6ff@suse.de>

On 1/6/21 11:00 PM, Muneendra wrote:
> This Patch added a unique application identifier i.e
> fc_app_id  member in blkcg which allows identification of traffic
> sources at an individual cgroup based Applications
> (ex:virtual machine (VM))level in both host and
> fabric infrastructure.
> 
> Added a new function blkcg_get_fc_appid to
> grab the app identifier associated with a bio.
> 
> Added a new function blkcg_set_fc_appid to
> set the app identifier in a blkcgrp associated with cgroup id
> 
> Added a new config BLK_CGROUP_FC_APPID and moved the changes
> under this config
> 
> Signed-off-by: Muneendra <muneendra.kumar at broadcom.com>
> 
> ---
> v7:
> Modified the Kconfig file
> 
> v6:
> Modified the Kconfig file as per standard specified
> in Documentation/process/coding-style.rst
> 
> v5:
> Renamed the arguments appropriatley
> Renamed APPID_LEN  to FC_APPID_LEN
> Moved the input validation at the begining of the function
> Modified the comments
> 
> v4:
> No change
> 
> v3:
> Renamed the functions and app_id to more specific
> 
> Addressed the reference leaks in blkcg_set_app_identifier
> 
> Added a new config BLK_CGROUP_FC_APPID and moved the changes
> under this config
> 
> Added blkcg_get_fc_appid,blkcg_set_fc_appid as inline functions
> 
> v2:
> renamed app_identifier to app_id
> removed the  sysfs interface blkio.app_identifie under
> ---
>   block/Kconfig              |  9 ++++++
>   include/linux/blk-cgroup.h | 56 ++++++++++++++++++++++++++++++++++++++
>   2 files changed, 65 insertions(+)
> 
Reviewed-by: Hannes Reinecke <hare at suse.de>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare at suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 N?rnberg
HRB 36809 (AG N?rnberg), Gesch?ftsf?hrer: Felix Imend?rffer


From hare at suse.de  Mon Jan 11 02:31:37 2021
From: hare at suse.de (Hannes Reinecke)
Date: Mon, 11 Jan 2021 08:31:37 +0100
Subject: [PATCH v7 03/16] nvme: Added a newsysfs attribute appid_store
In-Reply-To: <1609970430-19084-4-git-send-email-muneendra.kumar@broadcom.com>
References: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
 <1609970430-19084-4-git-send-email-muneendra.kumar@broadcom.com>
Message-ID: <de704af8-8419-76c6-c1f5-419406b2f807@suse.de>

On 1/6/21 11:00 PM, Muneendra wrote:
> Added a new sysfs attribute appid_store under
> /sys/class/fc/fc_udev_device/*
> 
> With this new interface the user can set the application identfier
> in  the blkcg associted with cgroup id.
> 
> Once the application identifer has set with this interface it allows
> identification of traffic sources at an individual cgroup based
> Applications (ex:virtual machine (VM))level in both host and
> fabric infrastructure(FC).
> 
> Below is the interface provided to set the app_id
> 
> echo "<cgroupid>:<appid>" >> /sys/class/fc/fc_udev_device/appid_store
> echo "457E:100000109b521d27" >> /sys/class/fc/fc_udev_device/appid_store
> 
> Signed-off-by: Muneendra <muneendra.kumar at broadcom.com>
> 
> ---
> v7:
> No change
> 
> v6:
> No change
> 
> v5:
> Replaced APPID_LEN with FC_APPID_LEN
> 
> v4:
> No change
> 
> v3:
> Replaced blkcg_set_app_identifier function with blkcg_set_fc_appid
> 
> v2:
> New Patch
> ---
>   drivers/nvme/host/fc.c | 73 +++++++++++++++++++++++++++++++++++++++++-
>   1 file changed, 72 insertions(+), 1 deletion(-)
> 
Reviewed-by: Hannes Reinecke <hare at suse.de>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare at suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 N?rnberg
HRB 36809 (AG N?rnberg), Gesch?ftsf?hrer: Felix Imend?rffer


From hare at suse.de  Mon Jan 11 02:32:30 2021
From: hare at suse.de (Hannes Reinecke)
Date: Mon, 11 Jan 2021 08:32:30 +0100
Subject: [PATCH v7 04/16] lpfc: vmid: Add the datastructure for supporting
 VMID in lpfc
In-Reply-To: <1609970430-19084-5-git-send-email-muneendra.kumar@broadcom.com>
References: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
 <1609970430-19084-5-git-send-email-muneendra.kumar@broadcom.com>
Message-ID: <7d50f389-91fe-2110-2ef5-fc4ce27293b9@suse.de>

On 1/6/21 11:00 PM, Muneendra wrote:
> From: Gaurav Srivastava <gaurav.srivastava at broadcom.com>
> 
> This patch adds the primary datastructures needed to implement VMID in lpfc
> driver. It maintains the capability, current state, hash table for the
> vmid/appid along with other information.
> 
> Signed-off-by: Gaurav Srivastava <gaurav.srivastava at broadcom.com>
> Signed-off-by: James Smart <jsmart2021 at gmail.com>
> 
> ---
> v7:
> No change
> 
> v6:
> No change
> 
> v5:
> No Change
> 
> v4:
> No change
> 
> v3:
> No change
> 
> v2:
> Ported the patch on top of 5.10/scsi-queue
> Removed unused variable.
> ---
>   drivers/scsi/lpfc/lpfc.h | 97 ++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 97 insertions(+)
> Reviewed-by: Hannes Reinecke <hare at suse.de>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare at suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 N?rnberg
HRB 36809 (AG N?rnberg), Gesch?ftsf?hrer: Felix Imend?rffer


From hare at suse.de  Mon Jan 11 02:33:21 2021
From: hare at suse.de (Hannes Reinecke)
Date: Mon, 11 Jan 2021 08:33:21 +0100
Subject: [PATCH v7 05/16] lpfc: vmid: Supplementary data structures for
 vmid and APIs
In-Reply-To: <1609970430-19084-6-git-send-email-muneendra.kumar@broadcom.com>
References: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
 <1609970430-19084-6-git-send-email-muneendra.kumar@broadcom.com>
Message-ID: <91bb4afd-a7de-12eb-cd27-a0e5ec72c6d6@suse.de>

On 1/6/21 11:00 PM, Muneendra wrote:
> From: Gaurav Srivastava <gaurav.srivastava at broadcom.com>
> 
> This patch adds additional data structures for supporting the two
> versions of vmid implementation. First type uses app header while
> the other types uses priority tagging mechanism. These data
> structures are used mostly for ELS and CT commands for the
> two vmid implementation.
> 
> The API determines if VMID is enabled by the user or not.
> 
> Signed-off-by: Gaurav Srivastava <gaurav.srivastava at broadcom.com>
> Signed-off-by: James Smart <jsmart2021 at gmail.com>
> 
> ---
> v7:
> No change
> 
> v6:
> No change
> 
> v5:
> Merged the patch5 of v4 to this patch
> Uniform data type naming scheme
> 
> v4:
> No change
> 
> v3:
> No change
> 
> v2:
> Ported the patch on top of 5.10/scsi-queue
> ---
>   drivers/scsi/lpfc/lpfc.h      |  24 +++++++
>   drivers/scsi/lpfc/lpfc_disc.h |   1 +
>   drivers/scsi/lpfc/lpfc_hw.h   | 124 ++++++++++++++++++++++++++++++++--
>   drivers/scsi/lpfc/lpfc_sli.h  |   8 +++
>   4 files changed, 153 insertions(+), 4 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare at suse.de>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare at suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 N?rnberg
HRB 36809 (AG N?rnberg), Gesch?ftsf?hrer: Felix Imend?rffer


From hare at suse.de  Mon Jan 11 02:35:13 2021
From: hare at suse.de (Hannes Reinecke)
Date: Mon, 11 Jan 2021 08:35:13 +0100
Subject: [PATCH v7 06/16] lpfc: vmid: Forward declarations for APIs
In-Reply-To: <1609970430-19084-7-git-send-email-muneendra.kumar@broadcom.com>
References: <1609970430-19084-1-git-send-email-muneendra.kumar@broadcom.com>
 <1609970430-19084-7-git-send-email-muneendra.kumar@broadcom.com>
Message-ID: <a6dcbb12-8525-c88f-3ddc-2cdce2b1a166@suse.de>

On 1/6/21 11:00 PM, Muneendra wrote:
> From: Gaurav Srivastava <gaurav.srivastava at broadcom.com>
> 
> This patch contains the forward declarations of commonly used APIs which
> are used outside the scope of the file.
> 
> Signed-off-by: Gaurav Srivastava <gaurav.srivastava at broadcom.com>
> Signed-off-by: James Smart <jsmart2021 at gmail.com>
> 
> ---
> v7:
> No change
> 
> v6:
> No change
> 
> v5:
> No change
> 
> v4:
> No change
> 
> v3:
> No change
> 
> v2:
> Ported the patch on top of 5.10/scsi-queue
> ---
>   drivers/scsi/lpfc/lpfc_crtn.h | 11 +++++++++++
>   1 file changed, 11 insertions(+)
> 
> diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
> index f78e52a18b0b..7eb0200ecaa8 100644
> --- a/drivers/scsi/lpfc/lpfc_crtn.h
> +++ b/drivers/scsi/lpfc/lpfc_crtn.h
> @@ -606,3 +606,14 @@ extern unsigned long lpfc_no_hba_reset[];
>   extern union lpfc_wqe128 lpfc_iread_cmd_template;
>   extern union lpfc_wqe128 lpfc_iwrite_cmd_template;
>   extern union lpfc_wqe128 lpfc_icmnd_cmd_template;
> +
> +/* vmid interface */
> +int lpfc_vmid_uvem(struct lpfc_vport *vport, struct lpfc_vmid *vmid, bool ins);
> +uint32_t lpfc_vmid_get_cs_ctl(struct lpfc_vport *vport);
> +int lpfc_vmid_cmd(struct lpfc_vport *vport,
> +		  int cmdcode, struct lpfc_vmid *vmid);
> +int lpfc_vmid_hash_fn(char *vmid, int len);
> +struct lpfc_vmid *lpfc_get_vmid_from_hastable(struct lpfc_vport *vport,
> +					      uint32_t hash, uint8_t *buf);
> +void lpfc_vmid_vport_cleanup(struct lpfc_vport *vport);
> +int lpfc_issue_els_qfpa(struct lpfc_vport *vport);
> 
I'd rather merge this patch with that patch defining the functions; but 
this is more a style issue.

Reviewed-by: Hannes Reinecke <hare at suse.de>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare at suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 N?rnberg
HRB 36809 (AG N?rnberg), Gesch?ftsf?hrer: Felix Imend?rffer


From hch at lst.de  Mon Jan 11 03:11:46 2021
From: hch at lst.de (Christoph Hellwig)
Date: Mon, 11 Jan 2021 09:11:46 +0100
Subject: [PATCH v2] nvmet-fc: associations list protected by rcu,
 instead of spinlock_irq where possible.
In-Reply-To: <1609697575-103348-1-git-send-email-leonid.ravich@dell.com>
References: <20201224110542.22219-1-leonid.ravich@dell.com>
 <1609697575-103348-1-git-send-email-leonid.ravich@dell.com>
Message-ID: <20210111081146.GA27116@lst.de>

James, can you review this patch?

On Sun, Jan 03, 2021 at 08:12:53PM +0200, leonid.ravich at dell.com wrote:
> From: Leonid Ravich <Leonid.Ravich at emc.com>
> 
> searching assoc_list protected by rcu_read_lock if list not changed inline.
> and according to the rcu list rules.
> 
> queue array embedded into nvmet_fc_tgt_assoc protected by rcu_read_lock
> according to rcu dereference/assign rules.
> 
> queue and assoc object freed after grace period by call_rcu.
> 
> tgtport lock taken for changing assoc_list.
> 
> Reviewed-by: Eldad Zinger <Eldad.Zinger at dell.com>
> Reviewed-by: Elad Grupi <Elad.Grupi at dell.com>
> Signed-off-by: Leonid Ravich <Leonid.Ravich at emc.com>
> ---
> 1) fixed sytle issus 
> 2) queues array protects by rcu as well
> 
>  drivers/nvme/target/fc.c | 81 +++++++++++++++++++++++-------------------------
>  1 file changed, 38 insertions(+), 43 deletions(-)
> 
> diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c
> index cd4e73a..c14c60b 100644
> --- a/drivers/nvme/target/fc.c
> +++ b/drivers/nvme/target/fc.c
> @@ -145,6 +145,7 @@ struct nvmet_fc_tgt_queue {
>  	struct list_head		avail_defer_list;
>  	struct workqueue_struct		*work_q;
>  	struct kref			ref;
> +	struct rcu_head			rcu;
>  	struct nvmet_fc_fcp_iod		fod[];		/* array of fcp_iods */
>  } __aligned(sizeof(unsigned long long));
>  
> @@ -167,6 +168,7 @@ struct nvmet_fc_tgt_assoc {
>  	struct nvmet_fc_tgt_queue	*queues[NVMET_NR_QUEUES + 1];
>  	struct kref			ref;
>  	struct work_struct		del_work;
> +	struct rcu_head			rcu;
>  };
>  
>  
> @@ -790,7 +792,6 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
>  			u16 qid, u16 sqsize)
>  {
>  	struct nvmet_fc_tgt_queue *queue;
> -	unsigned long flags;
>  	int ret;
>  
>  	if (qid > NVMET_NR_QUEUES)
> @@ -829,9 +830,7 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
>  		goto out_fail_iodlist;
>  
>  	WARN_ON(assoc->queues[qid]);
> -	spin_lock_irqsave(&assoc->tgtport->lock, flags);
> -	assoc->queues[qid] = queue;
> -	spin_unlock_irqrestore(&assoc->tgtport->lock, flags);
> +	rcu_assign_pointer(assoc->queues[qid], queue);
>  
>  	return queue;
>  
> @@ -851,11 +850,8 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
>  {
>  	struct nvmet_fc_tgt_queue *queue =
>  		container_of(ref, struct nvmet_fc_tgt_queue, ref);
> -	unsigned long flags;
>  
> -	spin_lock_irqsave(&queue->assoc->tgtport->lock, flags);
> -	queue->assoc->queues[queue->qid] = NULL;
> -	spin_unlock_irqrestore(&queue->assoc->tgtport->lock, flags);
> +	rcu_assign_pointer(queue->assoc->queues[queue->qid], NULL);
>  
>  	nvmet_fc_destroy_fcp_iodlist(queue->assoc->tgtport, queue);
>  
> @@ -863,7 +859,7 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
>  
>  	destroy_workqueue(queue->work_q);
>  
> -	kfree(queue);
> +	kfree_rcu(queue, rcu);
>  }
>  
>  static void
> @@ -965,24 +961,23 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
>  	struct nvmet_fc_tgt_queue *queue;
>  	u64 association_id = nvmet_fc_getassociationid(connection_id);
>  	u16 qid = nvmet_fc_getqueueid(connection_id);
> -	unsigned long flags;
>  
>  	if (qid > NVMET_NR_QUEUES)
>  		return NULL;
>  
> -	spin_lock_irqsave(&tgtport->lock, flags);
> -	list_for_each_entry(assoc, &tgtport->assoc_list, a_list) {
> +	rcu_read_lock();
> +	list_for_each_entry_rcu(assoc, &tgtport->assoc_list, a_list) {
>  		if (association_id == assoc->association_id) {
> -			queue = assoc->queues[qid];
> +			queue = rcu_dereference(assoc->queues[qid]);
>  			if (queue &&
>  			    (!atomic_read(&queue->connected) ||
>  			     !nvmet_fc_tgt_q_get(queue)))
>  				queue = NULL;
> -			spin_unlock_irqrestore(&tgtport->lock, flags);
> +			rcu_read_unlock();
>  			return queue;
>  		}
>  	}
> -	spin_unlock_irqrestore(&tgtport->lock, flags);
> +	rcu_read_unlock();
>  	return NULL;
>  }
>  
> @@ -1137,7 +1132,7 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
>  		}
>  		if (!needrandom) {
>  			assoc->association_id = ran;
> -			list_add_tail(&assoc->a_list, &tgtport->assoc_list);
> +			list_add_tail_rcu(&assoc->a_list, &tgtport->assoc_list);
>  		}
>  		spin_unlock_irqrestore(&tgtport->lock, flags);
>  	}
> @@ -1167,7 +1162,7 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
>  
>  	nvmet_fc_free_hostport(assoc->hostport);
>  	spin_lock_irqsave(&tgtport->lock, flags);
> -	list_del(&assoc->a_list);
> +	list_del_rcu(&assoc->a_list);
>  	oldls = assoc->rcv_disconn;
>  	spin_unlock_irqrestore(&tgtport->lock, flags);
>  	/* if pending Rcv Disconnect Association LS, send rsp now */
> @@ -1177,7 +1172,7 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
>  	dev_info(tgtport->dev,
>  		"{%d:%d} Association freed\n",
>  		tgtport->fc_target_port.port_num, assoc->a_id);
> -	kfree(assoc);
> +	kfree_rcu(assoc, rcu);
>  	nvmet_fc_tgtport_put(tgtport);
>  }
>  
> @@ -1198,7 +1193,6 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
>  {
>  	struct nvmet_fc_tgtport *tgtport = assoc->tgtport;
>  	struct nvmet_fc_tgt_queue *queue;
> -	unsigned long flags;
>  	int i, terminating;
>  
>  	terminating = atomic_xchg(&assoc->terminating, 1);
> @@ -1207,19 +1201,23 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
>  	if (terminating)
>  		return;
>  
> -	spin_lock_irqsave(&tgtport->lock, flags);
> +
>  	for (i = NVMET_NR_QUEUES; i >= 0; i--) {
> -		queue = assoc->queues[i];
> -		if (queue) {
> -			if (!nvmet_fc_tgt_q_get(queue))
> -				continue;
> -			spin_unlock_irqrestore(&tgtport->lock, flags);
> -			nvmet_fc_delete_target_queue(queue);
> -			nvmet_fc_tgt_q_put(queue);
> -			spin_lock_irqsave(&tgtport->lock, flags);
> +		rcu_read_lock();
> +		queue = rcu_dereference(assoc->queues[i]);
> +		if (!queue) {
> +			rcu_read_unlock();
> +			continue;
> +		}
> +
> +		if (!nvmet_fc_tgt_q_get(queue)) {
> +			rcu_read_unlock();
> +			continue;
>  		}
> +		rcu_read_unlock();
> +		nvmet_fc_delete_target_queue(queue);
> +		nvmet_fc_tgt_q_put(queue);
>  	}
> -	spin_unlock_irqrestore(&tgtport->lock, flags);
>  
>  	dev_info(tgtport->dev,
>  		"{%d:%d} Association deleted\n",
> @@ -1234,10 +1232,9 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
>  {
>  	struct nvmet_fc_tgt_assoc *assoc;
>  	struct nvmet_fc_tgt_assoc *ret = NULL;
> -	unsigned long flags;
>  
> -	spin_lock_irqsave(&tgtport->lock, flags);
> -	list_for_each_entry(assoc, &tgtport->assoc_list, a_list) {
> +	rcu_read_lock();
> +	list_for_each_entry_rcu(assoc, &tgtport->assoc_list, a_list) {
>  		if (association_id == assoc->association_id) {
>  			ret = assoc;
>  			if (!nvmet_fc_tgt_a_get(assoc))
> @@ -1245,7 +1242,7 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
>  			break;
>  		}
>  	}
> -	spin_unlock_irqrestore(&tgtport->lock, flags);
> +	rcu_read_unlock();
>  
>  	return ret;
>  }
> @@ -1473,19 +1470,17 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
>  static void
>  __nvmet_fc_free_assocs(struct nvmet_fc_tgtport *tgtport)
>  {
> -	struct nvmet_fc_tgt_assoc *assoc, *next;
> -	unsigned long flags;
> +	struct nvmet_fc_tgt_assoc *assoc;
>  
> -	spin_lock_irqsave(&tgtport->lock, flags);
> -	list_for_each_entry_safe(assoc, next,
> -				&tgtport->assoc_list, a_list) {
> +	rcu_read_lock();
> +	list_for_each_entry_rcu(assoc, &tgtport->assoc_list, a_list) {
>  		if (!nvmet_fc_tgt_a_get(assoc))
>  			continue;
>  		if (!schedule_work(&assoc->del_work))
>  			/* already deleting - release local reference */
>  			nvmet_fc_tgt_a_put(assoc);
>  	}
> -	spin_unlock_irqrestore(&tgtport->lock, flags);
> +	rcu_read_unlock();
>  }
>  
>  /**
> @@ -1568,16 +1563,16 @@ static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport,
>  			continue;
>  		spin_unlock_irqrestore(&nvmet_fc_tgtlock, flags);
>  
> -		spin_lock_irqsave(&tgtport->lock, flags);
> -		list_for_each_entry(assoc, &tgtport->assoc_list, a_list) {
> -			queue = assoc->queues[0];
> +		rcu_read_lock();
> +		list_for_each_entry_rcu(assoc, &tgtport->assoc_list, a_list) {
> +			queue = rcu_dereference(assoc->queues[0]);
>  			if (queue && queue->nvme_sq.ctrl == ctrl) {
>  				if (nvmet_fc_tgt_a_get(assoc))
>  					found_ctrl = true;
>  				break;
>  			}
>  		}
> -		spin_unlock_irqrestore(&tgtport->lock, flags);
> +		rcu_read_unlock();
>  
>  		nvmet_fc_tgtport_put(tgtport);
>  
> -- 
> 1.9.3
---end quoted text---


From pkuwangh at gmail.com  Mon Jan 11 03:56:09 2021
From: pkuwangh at gmail.com (Hao Wang)
Date: Mon, 11 Jan 2021 00:56:09 -0800
Subject: Data corruption when using multiple devices with NVMEoF TCP
In-Reply-To: <ae5b1654-e580-88be-0498-0cd111b53fa2@grimberg.me>
References: <CAJS6EdjsTVgs3JK3q2DePjEz1A0s9RJTOwqo=Ka7kinNMECtJw@mail.gmail.com>
 <2c0ff5ec-4ae2-ad29-67fb-4744514dab47@grimberg.me>
 <CAJS6Edh8aVAHhKRGqU+7v5C3KY7YxczVg_7Q8QrPGtyvVw7K3w@mail.gmail.com>
 <fd4541e4-78c5-ec3b-b272-467fd11f7472@grimberg.me>
 <20201223084332.GA30502@infradead.org>
 <CAJS6EdijX6ws_wHxygdpcYGtB6JFwLDbDE3A0t0QUYS-LbRakg@mail.gmail.com>
 <16d876c1-524a-38d3-3cff-99ec694464b2@grimberg.me>
 <CAJS6EdivEF0c=3FmKj4wGZoVRKbUvjH_qJLXmO7Tvwsp+km0rw@mail.gmail.com>
 <f631893c-5ce9-95fd-c32c-35a7e70d093c@grimberg.me>
 <CAJS6EdjUAb77-rWd=XmFhsM2_3Hds6VV6jQUVPJoJQHhk12J_Q@mail.gmail.com>
 <a6564a08-a3b0-5c22-51e3-712c4714bcc5@grimberg.me>
 <CAJS6Edgb+yCW5q5dA=MEkL0eYs4MXoopdiz72nhkxpkd5Fe_cA@mail.gmail.com>
 <ae5b1654-e580-88be-0498-0cd111b53fa2@grimberg.me>
Message-ID: <CAJS6Edjkfvs4pfH9XvwAT0h4STuoDh1PahSxkkTWOsKwgL5pZQ@mail.gmail.com>

Hey Sagi,

I exported 4 devices to the initiator, created a raid-0 array, and
copied a 98G directory with many ~100MB .gz files.
With the patch you give on top of 58cf05f597b0 (fairly new), I saw
about 24K prints from dmesg. Below are some of them:
[ 3775.256547] nvme_tcp: rq 22 (READ) data_len 131072 bio[1/2] sector
a388200 bvec: nsegs 19 size 77824 offset 0
[ 3775.256768] nvme_tcp: rq 19 (READ) data_len 131072 bio[1/2] sector
a388300 bvec: nsegs 19 size 77824 offset 0
[ 3775.256774] nvme_tcp: rq 20 (READ) data_len 131072 bio[1/2] sector
a388400 bvec: nsegs 19 size 77824 offset 0
[ 3775.256787] nvme_tcp: rq 5 (READ) data_len 131072 bio[1/2] sector
a388300 bvec: nsegs 19 size 77824 offset 0
[ 3775.256791] nvme_tcp: rq 6 (READ) data_len 131072 bio[1/2] sector
a388400 bvec: nsegs 19 size 77824 offset 0
[ 3775.256794] nvme_tcp: rq 117 (READ) data_len 131072 bio[1/2] sector
a388300 bvec: nsegs 19 size 77824 offset 0
[ 3775.256797] nvme_tcp: rq 118 (READ) data_len 131072 bio[1/2] sector
a388400 bvec: nsegs 19 size 77824 offset 0
[ 3775.256800] nvme_tcp: rq 5 (READ) data_len 262144 bio[1/4] sector
a388300 bvec: nsegs 19 size 77824 offset 0
[ 3775.257002] nvme_tcp: rq 21 (READ) data_len 131072 bio[1/2] sector
a388500 bvec: nsegs 19 size 77824 offset 0
[ 3775.257006] nvme_tcp: rq 22 (READ) data_len 131072 bio[1/2] sector
a388600 bvec: nsegs 19 size 77824 offset 0
[ 3775.257009] nvme_tcp: rq 7 (READ) data_len 131072 bio[1/2] sector
a388500 bvec: nsegs 19 size 77824 offset 0
[ 3775.257012] nvme_tcp: rq 8 (READ) data_len 131072 bio[1/2] sector
a388600 bvec: nsegs 19 size 77824 offset 0
[ 3775.257014] nvme_tcp: rq 7 (READ) data_len 131072 bio[1/2] sector
a388500 bvec: nsegs 19 size 77824 offset 0
[ 3775.257017] nvme_tcp: rq 8 (READ) data_len 131072 bio[1/2] sector
a388600 bvec: nsegs 19 size 77824 offset 0
[ 3775.257020] nvme_tcp: rq 6 (READ) data_len 262144 bio[1/4] sector
a388500 bvec: nsegs 19 size 77824 offset 0
[ 3775.262587] nvme_tcp: rq 22 (WRITE) data_len 131072 bio[1/2] sector
a388200 bvec: nsegs 19 size 77824 offset 0
[ 3775.262600] nvme_tcp: rq 22 (WRITE) data_len 131072 bio[2/2] sector
a388298 bvec: nsegs 13 size 53248 offset 0
[ 3775.262610] nvme_tcp: rq 5 (WRITE) data_len 262144 bio[1/4] sector
a388300 bvec: nsegs 19 size 77824 offset 0
[ 3775.262617] nvme_tcp: rq 5 (WRITE) data_len 262144 bio[2/4] sector
a388398 bvec: nsegs 13 size 53248 offset 0
[ 3775.262623] nvme_tcp: rq 5 (WRITE) data_len 262144 bio[3/4] sector
a388400 bvec: nsegs 19 size 77824 offset 0
[ 3775.262629] nvme_tcp: rq 5 (WRITE) data_len 262144 bio[4/4] sector
a388498 bvec: nsegs 13 size 53248 offset 0
[ 3775.262635] nvme_tcp: rq 6 (WRITE) data_len 262144 bio[1/4] sector
a388500 bvec: nsegs 19 size 77824 offset 0
[ 3775.262641] nvme_tcp: rq 6 (WRITE) data_len 262144 bio[2/4] sector
a388598 bvec: nsegs 13 size 53248 offset 0
[ 3775.262647] nvme_tcp: rq 6 (WRITE) data_len 262144 bio[3/4] sector
a388600 bvec: nsegs 19 size 77824 offset 0
[ 3775.262653] nvme_tcp: rq 6 (WRITE) data_len 262144 bio[4/4] sector
a388698 bvec: nsegs 13 size 53248 offset 0
[ 3775.263009] nvme_tcp: rq 5 (WRITE) data_len 131072 bio[1/2] sector
a388300 bvec: nsegs 19 size 77824 offset 0
[ 3775.263019] nvme_tcp: rq 5 (WRITE) data_len 131072 bio[2/2] sector
a388398 bvec: nsegs 13 size 53248 offset 0
[ 3775.263027] nvme_tcp: rq 6 (WRITE) data_len 131072 bio[1/2] sector
a388400 bvec: nsegs 19 size 77824 offset 0
[ 3775.263034] nvme_tcp: rq 6 (WRITE) data_len 131072 bio[2/2] sector
a388498 bvec: nsegs 13 size 53248 offset 0
[ 3775.263040] nvme_tcp: rq 7 (WRITE) data_len 131072 bio[1/2] sector
a388500 bvec: nsegs 19 size 77824 offset 0
[ 3775.263047] nvme_tcp: rq 7 (WRITE) data_len 131072 bio[2/2] sector
a388598 bvec: nsegs 13 size 53248 offset 0
[ 3775.263052] nvme_tcp: rq 8 (WRITE) data_len 131072 bio[1/2] sector
a388600 bvec: nsegs 19 size 77824 offset 0
[ 3775.263059] nvme_tcp: rq 8 (WRITE) data_len 131072 bio[2/2] sector
a388698 bvec: nsegs 13 size 53248 offset 0
[ 3775.264341] nvme_tcp: rq 19 (WRITE) data_len 131072 bio[1/2] sector
a388300 bvec: nsegs 19 size 77824 offset 0
[ 3775.264353] nvme_tcp: rq 19 (WRITE) data_len 131072 bio[2/2] sector
a388398 bvec: nsegs 13 size 53248 offset 0
[ 3775.264361] nvme_tcp: rq 20 (WRITE) data_len 131072 bio[1/2] sector
a388400 bvec: nsegs 19 size 77824 offset 0
[ 3775.264369] nvme_tcp: rq 20 (WRITE) data_len 131072 bio[2/2] sector
a388498 bvec: nsegs 13 size 53248 offset 0
[ 3775.264380] nvme_tcp: rq 21 (WRITE) data_len 131072 bio[1/2] sector
a388500 bvec: nsegs 19 size 77824 offset 0
[ 3775.264387] nvme_tcp: rq 21 (WRITE) data_len 131072 bio[2/2] sector
a388598 bvec: nsegs 13 size 53248 offset 0
[ 3775.264410] nvme_tcp: rq 22 (WRITE) data_len 131072 bio[1/2] sector
a388600 bvec: nsegs 19 size 77824 offset 0

Hao

On Tue, Jan 5, 2021 at 5:53 PM Sagi Grimberg <sagi at grimberg.me> wrote:
>
> Hey Hao,
>
> > Okay, will do that in a few days. Something else just popped up and I
> > have a limited time window to use some machines.
> >
> > BTW, what is the performance implication of disabling merge? My usage
> > pattern is mostly sequential read and write, and write bandwidth is
> > pretty high.
>
> Did you get a chance to look into this?


From sagi at grimberg.me  Mon Jan 11 05:11:01 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Mon, 11 Jan 2021 02:11:01 -0800
Subject: Data corruption when using multiple devices with NVMEoF TCP
In-Reply-To: <CAJS6Edjkfvs4pfH9XvwAT0h4STuoDh1PahSxkkTWOsKwgL5pZQ@mail.gmail.com>
References: <CAJS6EdjsTVgs3JK3q2DePjEz1A0s9RJTOwqo=Ka7kinNMECtJw@mail.gmail.com>
 <2c0ff5ec-4ae2-ad29-67fb-4744514dab47@grimberg.me>
 <CAJS6Edh8aVAHhKRGqU+7v5C3KY7YxczVg_7Q8QrPGtyvVw7K3w@mail.gmail.com>
 <fd4541e4-78c5-ec3b-b272-467fd11f7472@grimberg.me>
 <20201223084332.GA30502@infradead.org>
 <CAJS6EdijX6ws_wHxygdpcYGtB6JFwLDbDE3A0t0QUYS-LbRakg@mail.gmail.com>
 <16d876c1-524a-38d3-3cff-99ec694464b2@grimberg.me>
 <CAJS6EdivEF0c=3FmKj4wGZoVRKbUvjH_qJLXmO7Tvwsp+km0rw@mail.gmail.com>
 <f631893c-5ce9-95fd-c32c-35a7e70d093c@grimberg.me>
 <CAJS6EdjUAb77-rWd=XmFhsM2_3Hds6VV6jQUVPJoJQHhk12J_Q@mail.gmail.com>
 <a6564a08-a3b0-5c22-51e3-712c4714bcc5@grimberg.me>
 <CAJS6Edgb+yCW5q5dA=MEkL0eYs4MXoopdiz72nhkxpkd5Fe_cA@mail.gmail.com>
 <ae5b1654-e580-88be-0498-0cd111b53fa2@grimberg.me>
 <CAJS6Edjkfvs4pfH9XvwAT0h4STuoDh1PahSxkkTWOsKwgL5pZQ@mail.gmail.com>
Message-ID: <16fe1e9c-3a43-ef28-7b69-755e6a86464f@grimberg.me>


> Hey Sagi,

Hey Hao,

> I exported 4 devices to the initiator, created a raid-0 array, and
> copied a 98G directory with many ~100MB .gz files.
> With the patch you give on top of 58cf05f597b0 (fairly new), I saw
> about 24K prints from dmesg. Below are some of them:

Yes, I understand it generated tons of prints, but it seems that
something is strange here.

> [ 3775.256547] nvme_tcp: rq 22 (READ) data_len 131072 bio[1/2] sector
> a388200 bvec: nsegs 19 size 77824 offset 0

This is a read request and has 2 bios, one spans 19 4K buffers (starting
from sector a388200) and the second probably spans 13 4K buffers. The
host is asking the target to send 128K (data_len 131072), but I don't
see anywhere that the host is receiving the residual of the data
transfer..

Should be in the form of:

nvme_tcp: rq 22 (READ) data_len 131072 bio[2/2] sector 0xa388298 bvec: 
nsegs 13 size 53248 offset 0

In your entire log, do you see any (READ) print that spans bio that
is not [1/x]? e.g. a read that spans other bios in the request (like
[2/2], [2/3], etc..)?

> [ 3775.256768] nvme_tcp: rq 19 (READ) data_len 131072 bio[1/2] sector
> a388300 bvec: nsegs 19 size 77824 offset 0
> [ 3775.256774] nvme_tcp: rq 20 (READ) data_len 131072 bio[1/2] sector
> a388400 bvec: nsegs 19 size 77824 offset 0
> [ 3775.256787] nvme_tcp: rq 5 (READ) data_len 131072 bio[1/2] sector
> a388300 bvec: nsegs 19 size 77824 offset 0
> [ 3775.256791] nvme_tcp: rq 6 (READ) data_len 131072 bio[1/2] sector
> a388400 bvec: nsegs 19 size 77824 offset 0
> [ 3775.256794] nvme_tcp: rq 117 (READ) data_len 131072 bio[1/2] sector
> a388300 bvec: nsegs 19 size 77824 offset 0
> [ 3775.256797] nvme_tcp: rq 118 (READ) data_len 131072 bio[1/2] sector
> a388400 bvec: nsegs 19 size 77824 offset 0
> [ 3775.256800] nvme_tcp: rq 5 (READ) data_len 262144 bio[1/4] sector
> a388300 bvec: nsegs 19 size 77824 offset 0
> [ 3775.257002] nvme_tcp: rq 21 (READ) data_len 131072 bio[1/2] sector
> a388500 bvec: nsegs 19 size 77824 offset 0
> [ 3775.257006] nvme_tcp: rq 22 (READ) data_len 131072 bio[1/2] sector
> a388600 bvec: nsegs 19 size 77824 offset 0
> [ 3775.257009] nvme_tcp: rq 7 (READ) data_len 131072 bio[1/2] sector
> a388500 bvec: nsegs 19 size 77824 offset 0
> [ 3775.257012] nvme_tcp: rq 8 (READ) data_len 131072 bio[1/2] sector
> a388600 bvec: nsegs 19 size 77824 offset 0
> [ 3775.257014] nvme_tcp: rq 7 (READ) data_len 131072 bio[1/2] sector
> a388500 bvec: nsegs 19 size 77824 offset 0
> [ 3775.257017] nvme_tcp: rq 8 (READ) data_len 131072 bio[1/2] sector
> a388600 bvec: nsegs 19 size 77824 offset 0
> [ 3775.257020] nvme_tcp: rq 6 (READ) data_len 262144 bio[1/4] sector
> a388500 bvec: nsegs 19 size 77824 offset 0
> [ 3775.262587] nvme_tcp: rq 22 (WRITE) data_len 131072 bio[1/2] sector
> a388200 bvec: nsegs 19 size 77824 offset 0
> [ 3775.262600] nvme_tcp: rq 22 (WRITE) data_len 131072 bio[2/2] sector
> a388298 bvec: nsegs 13 size 53248 offset 0

For (WRITE) request we see the desired sequence, we first write the
content of the first bio (19 4K segments) and then the content of the
second bio (13 4K segments).

> [ 3775.262610] nvme_tcp: rq 5 (WRITE) data_len 262144 bio[1/4] sector
> a388300 bvec: nsegs 19 size 77824 offset 0
> [ 3775.262617] nvme_tcp: rq 5 (WRITE) data_len 262144 bio[2/4] sector
> a388398 bvec: nsegs 13 size 53248 offset 0
> [ 3775.262623] nvme_tcp: rq 5 (WRITE) data_len 262144 bio[3/4] sector
> a388400 bvec: nsegs 19 size 77824 offset 0
> [ 3775.262629] nvme_tcp: rq 5 (WRITE) data_len 262144 bio[4/4] sector
> a388498 bvec: nsegs 13 size 53248 offset 0

Same here and on...

> [ 3775.262635] nvme_tcp: rq 6 (WRITE) data_len 262144 bio[1/4] sector
> a388500 bvec: nsegs 19 size 77824 offset 0
> [ 3775.262641] nvme_tcp: rq 6 (WRITE) data_len 262144 bio[2/4] sector
> a388598 bvec: nsegs 13 size 53248 offset 0
> [ 3775.262647] nvme_tcp: rq 6 (WRITE) data_len 262144 bio[3/4] sector
> a388600 bvec: nsegs 19 size 77824 offset 0
> [ 3775.262653] nvme_tcp: rq 6 (WRITE) data_len 262144 bio[4/4] sector
> a388698 bvec: nsegs 13 size 53248 offset 0
> [ 3775.263009] nvme_tcp: rq 5 (WRITE) data_len 131072 bio[1/2] sector
> a388300 bvec: nsegs 19 size 77824 offset 0
> [ 3775.263019] nvme_tcp: rq 5 (WRITE) data_len 131072 bio[2/2] sector
> a388398 bvec: nsegs 13 size 53248 offset 0
> [ 3775.263027] nvme_tcp: rq 6 (WRITE) data_len 131072 bio[1/2] sector
> a388400 bvec: nsegs 19 size 77824 offset 0
> [ 3775.263034] nvme_tcp: rq 6 (WRITE) data_len 131072 bio[2/2] sector
> a388498 bvec: nsegs 13 size 53248 offset 0
> [ 3775.263040] nvme_tcp: rq 7 (WRITE) data_len 131072 bio[1/2] sector
> a388500 bvec: nsegs 19 size 77824 offset 0
> [ 3775.263047] nvme_tcp: rq 7 (WRITE) data_len 131072 bio[2/2] sector
> a388598 bvec: nsegs 13 size 53248 offset 0
> [ 3775.263052] nvme_tcp: rq 8 (WRITE) data_len 131072 bio[1/2] sector
> a388600 bvec: nsegs 19 size 77824 offset 0
> [ 3775.263059] nvme_tcp: rq 8 (WRITE) data_len 131072 bio[2/2] sector
> a388698 bvec: nsegs 13 size 53248 offset 0
> [ 3775.264341] nvme_tcp: rq 19 (WRITE) data_len 131072 bio[1/2] sector
> a388300 bvec: nsegs 19 size 77824 offset 0
> [ 3775.264353] nvme_tcp: rq 19 (WRITE) data_len 131072 bio[2/2] sector
> a388398 bvec: nsegs 13 size 53248 offset 0
> [ 3775.264361] nvme_tcp: rq 20 (WRITE) data_len 131072 bio[1/2] sector
> a388400 bvec: nsegs 19 size 77824 offset 0
> [ 3775.264369] nvme_tcp: rq 20 (WRITE) data_len 131072 bio[2/2] sector
> a388498 bvec: nsegs 13 size 53248 offset 0
> [ 3775.264380] nvme_tcp: rq 21 (WRITE) data_len 131072 bio[1/2] sector
> a388500 bvec: nsegs 19 size 77824 offset 0
> [ 3775.264387] nvme_tcp: rq 21 (WRITE) data_len 131072 bio[2/2] sector
> a388598 bvec: nsegs 13 size 53248 offset 0
> [ 3775.264410] nvme_tcp: rq 22 (WRITE) data_len 131072 bio[1/2] sector
> a388600 bvec: nsegs 19 size 77824 offset 0

 From the code it seems like it should do the right thing assuming
that the data does arrive, will look deeper.

Thanks for helping to dissect this issue.


From minwoo.im.dev at gmail.com  Mon Jan 11 07:27:48 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Mon, 11 Jan 2021 21:27:48 +0900
Subject: [PATCH 3/3] nvme: add parameter command_retry to enable retry
In-Reply-To: <dfe59030-3eab-a178-7264-792f76dffe4c@huawei.com>
References: <20210108144659.7126-1-minwoo.im.dev@gmail.com>
 <20210108144659.7126-4-minwoo.im.dev@gmail.com>
 <dfe59030-3eab-a178-7264-792f76dffe4c@huawei.com>
Message-ID: <20210111122748.GA6831@localhost.localdomain>

Hello,

On 21-01-11 11:47:56, Chao Leng wrote:
> 
> 
> On 2021/1/8 22:46, Minwoo Im wrote:
> > nvme_init_request() has set REQ_FAILFAST_DRIVER to make requests
> > non-retryable.  This command flag value is checked in
> > nvme_decide_disposition() to decide whether to RETRY or other
> > operations.  In that point, blk_noretry_request() macro will be used to
> > check if command flags have one of REQ_FAILFAST_*.  If so, it just
> > decides to complete the request without retrying.
> > 
> > This patch added a module parameter named command_retry to turn on the
> > command retry feature in this driver.  If turning it on,
> > REQ3_FAILFAST_DRIVER will not be set to requests so that retry can be
> > reached out to nvme_retry_req() based on the module parameter.
> > 
> > Signed-off-by: Minwoo Im <minwoo.im.dev at gmail.com>
> > ---
> >   drivers/nvme/host/core.c | 7 ++++++-
> >   1 file changed, 6 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
> > index 6e428fdc25a8..e1836ca9956f 100644
> > --- a/drivers/nvme/host/core.c
> > +++ b/drivers/nvme/host/core.c
> > @@ -44,6 +44,10 @@ static unsigned char shutdown_timeout = 5;
> >   module_param(shutdown_timeout, byte, 0644);
> >   MODULE_PARM_DESC(shutdown_timeout, "timeout in seconds for controller shutdown");
> > +static bool command_retry;
> > +module_param(command_retry, bool, 0644);
> > +MODULE_PARM_DESC(command_retry, "retry commands up to nvme_max_retries");
> > +
> >   static u8 nvme_max_retries = 5;
> >   module_param_named(max_retries, nvme_max_retries, byte, 0644);
> >   MODULE_PARM_DESC(max_retries, "max number of retries a command may have");
> > @@ -560,7 +564,8 @@ static inline void nvme_init_request(struct request *req,
> >   	else /* no queuedata implies admin queue */
> >   		req->timeout = NVME_ADMIN_TIMEOUT;
> > -	req->cmd_flags |= REQ_FAILFAST_DRIVER;
> > +	if (!command_retry)
> > +		req->cmd_flags |= REQ_FAILFAST_DRIVER;
> In abnormal scenarios, such as request time out, connection process may takes long time or the admin command waits for long time.
> Retry only for non-host errors may be a better choice. Maybe we can make some optimizations in nvme_decide_disposition.

Thanks for your review!

Oh, I agreed that it might wait for so long time in connecting process.
Restricting some of commands that should be retried would be better as
you mentiond.

Do you mean that maybe we can check this module parameter in
nvme_decide_disposition()?  Like, even if blk_noretry_request(req) says
that it's non-retriable, if this module parameter is enabled, then we
can retry rather than failfast?

Thanks,


From hare at suse.de  Mon Jan 11 11:00:18 2021
From: hare at suse.de (Hannes Reinecke)
Date: Mon, 11 Jan 2021 17:00:18 +0100
Subject: [PATCH] nvme: hwmon: fix crash on device teardown
In-Reply-To: <20210105094545.3tq7c6ev5yn3bhyi@beryllium.lan>
References: <20201209213228.5044-1-ematsumiya@suse.de>
 <4ebb1b8c-4bb0-6ebf-3417-d4aee1bdd3a8@suse.de>
 <20201230143805.2v4izgkzbnisssvr@beryllium.lan>
 <20201230151653.ozlqlwef7f2tarwz@beryllium.lan>
 <20201230153138.4f2jd2yd2vkqndby@beryllium.lan>
 <20210104210610.hliiupywksawgei3@hyori>
 <20210105094545.3tq7c6ev5yn3bhyi@beryllium.lan>
Message-ID: <412d45ef-40af-24c3-4aa2-042ecbba05cd@suse.de>

On 1/5/21 10:45 AM, Daniel Wagner wrote:
> On Mon, Jan 04, 2021 at 06:06:10PM -0300, Enzo Matsumiya wrote:
>> @Daniel maybe try tweaking your tests to use a smaller controller
>> loss timeout (-l option)? I do this on my tests because the default
>> value kicks in about 30min after hot-removal -- i.e. you
>> have to actually wait for the timeout to expire to trigger the bug.
> 
> As far I can tell, the blktests test I am using will trigger the same
> bug. The problem is that the lifetime of hwmon sysfs entry should be
> aligned to the lifetime of the nvme sysfs entry. Currently, hwmon's
> lifetime is bound to the lifetime of the ctl sysfs entry. When the nvme
> entry goes away (and obviously also the underlying device), the hwmon
> sysfs entry still references it.
> 
Yeah, using the controller node for devm allocations is quite dodgy.
Does this one help?


diff --git a/drivers/nvme/host/hwmon.c b/drivers/nvme/host/hwmon.c
index 6fdd07fb3001..7260af028cf7 100644
--- a/drivers/nvme/host/hwmon.c
+++ b/drivers/nvme/host/hwmon.c
@@ -226,7 +226,7 @@ static const struct hwmon_chip_info

  int nvme_hwmon_init(struct nvme_ctrl *ctrl)
  {
-       struct device *dev = ctrl->dev;
+       struct device *dev = ctrl->device;
         struct nvme_hwmon_data *data;
         struct device *hwmon;
         int err;
@@ -240,8 +240,7 @@ int nvme_hwmon_init(struct nvme_ctrl *ctrl)

         err = nvme_hwmon_get_smart_log(data);
         if (err) {
-               dev_warn(ctrl->device,
-                       "Failed to read smart log (error %d)\n", err);
+               dev_warn(dev, "Failed to read smart log (error %d)\n", err);
                 devm_kfree(dev, data);
                 return err;
         }


Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare at suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 N?rnberg
HRB 36809 (AG N?rnberg), Gesch?ftsf?hrer: Felix Imend?rffer


From hch at lst.de  Mon Jan 11 11:06:33 2021
From: hch at lst.de (Christoph Hellwig)
Date: Mon, 11 Jan 2021 17:06:33 +0100
Subject: [PATCH] nvme: hwmon: fix crash on device teardown
In-Reply-To: <412d45ef-40af-24c3-4aa2-042ecbba05cd@suse.de>
References: <20201209213228.5044-1-ematsumiya@suse.de>
 <4ebb1b8c-4bb0-6ebf-3417-d4aee1bdd3a8@suse.de>
 <20201230143805.2v4izgkzbnisssvr@beryllium.lan>
 <20201230151653.ozlqlwef7f2tarwz@beryllium.lan>
 <20201230153138.4f2jd2yd2vkqndby@beryllium.lan>
 <20210104210610.hliiupywksawgei3@hyori>
 <20210105094545.3tq7c6ev5yn3bhyi@beryllium.lan>
 <412d45ef-40af-24c3-4aa2-042ecbba05cd@suse.de>
Message-ID: <20210111160633.GA27554@lst.de>

We could just stop using devm and do explicit resource management.

Btw, for the next patch please cc the author of the nvme-hwmon code.


From dwagner at suse.de  Mon Jan 11 11:18:57 2021
From: dwagner at suse.de (Daniel Wagner)
Date: Mon, 11 Jan 2021 17:18:57 +0100
Subject: [PATCH] nvme: hwmon: fix crash on device teardown
In-Reply-To: <412d45ef-40af-24c3-4aa2-042ecbba05cd@suse.de>
References: <20201209213228.5044-1-ematsumiya@suse.de>
 <4ebb1b8c-4bb0-6ebf-3417-d4aee1bdd3a8@suse.de>
 <20201230143805.2v4izgkzbnisssvr@beryllium.lan>
 <20201230151653.ozlqlwef7f2tarwz@beryllium.lan>
 <20201230153138.4f2jd2yd2vkqndby@beryllium.lan>
 <20210104210610.hliiupywksawgei3@hyori>
 <20210105094545.3tq7c6ev5yn3bhyi@beryllium.lan>
 <412d45ef-40af-24c3-4aa2-042ecbba05cd@suse.de>
Message-ID: <20210111161857.okecoo4h4b4prpic@beryllium.lan>

On Mon, Jan 11, 2021 at 05:00:18PM +0100, Hannes Reinecke wrote:
> Yeah, using the controller node for devm allocations is quite dodgy.
> Does this one help?
> 
> diff --git a/drivers/nvme/host/hwmon.c b/drivers/nvme/host/hwmon.c
> index 6fdd07fb3001..7260af028cf7 100644
> --- a/drivers/nvme/host/hwmon.c
> +++ b/drivers/nvme/host/hwmon.c
> @@ -226,7 +226,7 @@ static const struct hwmon_chip_info
> 
>  int nvme_hwmon_init(struct nvme_ctrl *ctrl)
>  {
> -       struct device *dev = ctrl->dev;
> +       struct device *dev = ctrl->device;

This is what I tried. Yes, it fixes the obvious problem and moves the
hwmon entry under the nvme entry. When the nvme is destroyed, the hwmon
entry is not accessible. But as ctrl->device is not managed by devm the
resources are not freed.



From revanth.rajashekar at intel.com  Mon Jan 11 11:26:02 2021
From: revanth.rajashekar at intel.com (Revanth Rajashekar)
Date: Mon, 11 Jan 2021 09:26:02 -0700
Subject: [PATCH] nvme: Check the PRINFO bit and the Metadata size before
 deciding the host buffer length
Message-ID: <20210111162602.29305-1-revanth.rajashekar@intel.com>

According to NVMe spec v1.4, section 8.3.1, the PRINFO bit and
the metadata size play a vital role in deteriming the host buffer
size.

If PRIFNO bit is set and MS==8, the host doesn't add the metadata
buffer, instead the controller adds it.

Signed-off-by: Revanth Rajashekar <revanth.rajashekar at intel.com>
---
 drivers/nvme/host/core.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 7a9642719..5efacd596 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -1273,12 +1273,14 @@ static void __user *nvme_to_user_ptr(uintptr_t ptrval)
 	return (void __user *)ptrval;
 }

+#define NVME_PRINFO_CTRL_BIT (13)
 static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
 {
 	struct nvme_user_io io;
 	struct nvme_command c;
 	unsigned length, meta_len;
 	void __user *metadata;
+	unsigned long control;

 	if (copy_from_user(&io, uio, sizeof(io)))
 		return -EFAULT;
@@ -1297,6 +1299,12 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
 	length = (io.nblocks + 1) << ns->lba_shift;
 	meta_len = (io.nblocks + 1) * ns->ms;
 	metadata = nvme_to_user_ptr(io.metadata);
+	control = cpu_to_le16(io.control);
+
+	if (test_bit(NVME_PRINFO_CTRL_BIT, &control) && ns->ms == 8) {
+		meta_len = 0;
+		metadata = NULL;
+	}

 	if (ns->ext) {
 		length += meta_len;
--
2.17.1



From kbusch at kernel.org  Mon Jan 11 11:47:29 2021
From: kbusch at kernel.org (Keith Busch)
Date: Mon, 11 Jan 2021 08:47:29 -0800
Subject: [PATCH] nvme: Check the PRINFO bit and the Metadata size before
 deciding the host buffer length
In-Reply-To: <20210111162602.29305-1-revanth.rajashekar@intel.com>
References: <20210111162602.29305-1-revanth.rajashekar@intel.com>
Message-ID: <20210111164729.GB1458209@dhcp-10-100-145-180.wdc.com>

On Mon, Jan 11, 2021 at 09:26:02AM -0700, Revanth Rajashekar wrote:
> +#define NVME_PRINFO_CTRL_BIT (13)

This bit already defined as 'NVME_RW_PRINFO_PRACT'.

>  static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
>  {
>  	struct nvme_user_io io;
>  	struct nvme_command c;
>  	unsigned length, meta_len;
>  	void __user *metadata;
> +	unsigned long control;

You can remove this variable.

> 
>  	if (copy_from_user(&io, uio, sizeof(io)))
>  		return -EFAULT;
> @@ -1297,6 +1299,12 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
>  	length = (io.nblocks + 1) << ns->lba_shift;
>  	meta_len = (io.nblocks + 1) * ns->ms;
>  	metadata = nvme_to_user_ptr(io.metadata);
> +	control = cpu_to_le16(io.control);

You're checking the bit with the CPU arch's native endianness, so you
shouldn't be byte swapping here for BE archs.

> +	if (test_bit(NVME_PRINFO_CTRL_BIT, &control) && ns->ms == 8) {

No need for the "test_bit()" here, you can just do:

	if (io.control & NVME_RW_PRINFO_PRACT && ms == 8)) 

> +		meta_len = 0;
> +		metadata = NULL;
> +	}


From kbusch at kernel.org  Mon Jan 11 12:01:10 2021
From: kbusch at kernel.org (Keith Busch)
Date: Mon, 11 Jan 2021 09:01:10 -0800
Subject: [PATCH] nvme: trace: parse format nvm command in detail
In-Reply-To: <CAPcyv4jLWOKDTyGzwar4C0H5euggvD_Ak6NESLd9=1THGC=ASg@mail.gmail.com>
References: <20210104155343.GA26034@michal-desk>
 <20210104160220.GB1024941@dhcp-10-100-145-180.wdc.com>
 <20210106090053.GA32643@lst.de>
 <20210108223431.GA1451691@dhcp-10-100-145-180.wdc.com>
 <CAPcyv4jLWOKDTyGzwar4C0H5euggvD_Ak6NESLd9=1THGC=ASg@mail.gmail.com>
Message-ID: <20210111170110.GC1458209@dhcp-10-100-145-180.wdc.com>

On Fri, Jan 08, 2021 at 04:12:31PM -0800, Dan Williams wrote:
> Is there a more centralized place to land such a helper? trace-cmd,
> perf? The nice thing about kernel parsing is I don't need to have a
> separate pile of disparate tools across subsystems.

Yes, I just placed it in a temporary location to see if the other nvme
stakeholders are okay with the idea. If so, I can make a real patch
series to remove the in-kernel decoding, and add the parsing script
somewhere in tools/.


From dan.j.williams at intel.com  Mon Jan 11 12:10:34 2021
From: dan.j.williams at intel.com (Dan Williams)
Date: Mon, 11 Jan 2021 09:10:34 -0800
Subject: [PATCH] nvme: trace: parse format nvm command in detail
In-Reply-To: <20210111170110.GC1458209@dhcp-10-100-145-180.wdc.com>
References: <20210104155343.GA26034@michal-desk>
 <20210104160220.GB1024941@dhcp-10-100-145-180.wdc.com>
 <20210106090053.GA32643@lst.de>
 <20210108223431.GA1451691@dhcp-10-100-145-180.wdc.com>
 <CAPcyv4jLWOKDTyGzwar4C0H5euggvD_Ak6NESLd9=1THGC=ASg@mail.gmail.com>
 <20210111170110.GC1458209@dhcp-10-100-145-180.wdc.com>
Message-ID: <CAPcyv4g3LKRmUOj1QHmkQ5rZ4BfH6TQaK6jKhXfb2DoBW-MoUQ@mail.gmail.com>

On Mon, Jan 11, 2021 at 9:01 AM Keith Busch <kbusch at kernel.org> wrote:
>
> On Fri, Jan 08, 2021 at 04:12:31PM -0800, Dan Williams wrote:
> > Is there a more centralized place to land such a helper? trace-cmd,
> > perf? The nice thing about kernel parsing is I don't need to have a
> > separate pile of disparate tools across subsystems.
>
> Yes, I just placed it in a temporary location to see if the other nvme
> stakeholders are okay with the idea. If so, I can make a real patch
> series to remove the in-kernel decoding, and add the parsing script
> somewhere in tools/.

"Somewhere in tools/" is still not quite what I'm asking for, I want
something nearly as automatic and seamless as the kernel ftrace pipe.
If I need nvme tools for nvme events and mce tools for mce events etc,
I'd rather just have decode in the kernel. Perhaps this is a use case
for a usermode helper that accompanies a new kernel tracing file?. If
the helper exists the events supported events are decoded if the
helper is missing the interface is equivalent to the raw formatted
events. Decoded events "just work".


From kbusch at kernel.org  Mon Jan 11 12:50:18 2021
From: kbusch at kernel.org (Keith Busch)
Date: Mon, 11 Jan 2021 09:50:18 -0800
Subject: [PATCH] nvme: trace: parse format nvm command in detail
In-Reply-To: <CAPcyv4g3LKRmUOj1QHmkQ5rZ4BfH6TQaK6jKhXfb2DoBW-MoUQ@mail.gmail.com>
References: <20210104155343.GA26034@michal-desk>
 <20210104160220.GB1024941@dhcp-10-100-145-180.wdc.com>
 <20210106090053.GA32643@lst.de>
 <20210108223431.GA1451691@dhcp-10-100-145-180.wdc.com>
 <CAPcyv4jLWOKDTyGzwar4C0H5euggvD_Ak6NESLd9=1THGC=ASg@mail.gmail.com>
 <20210111170110.GC1458209@dhcp-10-100-145-180.wdc.com>
 <CAPcyv4g3LKRmUOj1QHmkQ5rZ4BfH6TQaK6jKhXfb2DoBW-MoUQ@mail.gmail.com>
Message-ID: <20210111175018.GD1458209@dhcp-10-100-145-180.wdc.com>

On Mon, Jan 11, 2021 at 09:10:34AM -0800, Dan Williams wrote:
> On Mon, Jan 11, 2021 at 9:01 AM Keith Busch <kbusch at kernel.org> wrote:
> >
> > On Fri, Jan 08, 2021 at 04:12:31PM -0800, Dan Williams wrote:
> > > Is there a more centralized place to land such a helper? trace-cmd,
> > > perf? The nice thing about kernel parsing is I don't need to have a
> > > separate pile of disparate tools across subsystems.
> >
> > Yes, I just placed it in a temporary location to see if the other nvme
> > stakeholders are okay with the idea. If so, I can make a real patch
> > series to remove the in-kernel decoding, and add the parsing script
> > somewhere in tools/.
> 
> "Somewhere in tools/" is still not quite what I'm asking for, I want
> something nearly as automatic and seamless as the kernel ftrace pipe.
> If I need nvme tools for nvme events and mce tools for mce events etc,
> I'd rather just have decode in the kernel. Perhaps this is a use case
> for a usermode helper that accompanies a new kernel tracing file?. If
> the helper exists the events supported events are decoded if the
> helper is missing the interface is equivalent to the raw formatted
> events. Decoded events "just work".

My only concern is that decoding omits fields, so you have to ugprade
your kernel in order to see the missing ones when the current kernel's
decoding doesn't "just work". If that's how people want to maintain
them, then I won't object any longer.


From james.smart at broadcom.com  Mon Jan 11 13:12:23 2021
From: james.smart at broadcom.com (James Smart)
Date: Mon, 11 Jan 2021 10:12:23 -0800
Subject: [PATCH] nvmet-fc: associations list replaced with hlist rcu,
In-Reply-To: <20201224110542.22219-2-leonid.ravich@dell.com>
References: <20201224110542.22219-1-leonid.ravich@dell.com>
 <20201224110542.22219-2-leonid.ravich@dell.com>
Message-ID: <7478952e-cc5d-6d63-8a33-37bcad1cce59@broadcom.com>

On 12/24/2020 3:05 AM, leonid.ravich at dell.com wrote:
> From: Leonid Ravich <Leonid.Ravich at emc.com>
>
> to remove locking from nvmet_fc_find_target_queue
> which called per IO.
>
> Signed-off-by: Leonid Ravich <Leonid.Ravich at emc.com>
> ---
>   drivers/nvme/target/fc.c | 54 ++++++++++++++++++++++++++++--------------------
>   1 file changed, 32 insertions(+), 22 deletions(-)

was this replaced by the v2 patch ?

-- james



-- 
This electronic communication and the information and any files transmitted 
with it, or attached to it, are confidential and are intended solely for 
the use of the individual or entity to whom it is addressed and may contain 
information that is confidential, legally privileged, protected by privacy 
laws, or otherwise restricted from disclosure to anyone else. If you are 
not the intended recipient or the person responsible for delivering the 
e-mail to the intended recipient, you are hereby notified that any use, 
copying, distributing, dissemination, forwarding, printing, or copying of 
this e-mail is strictly prohibited. If you received this e-mail in error, 
please return the e-mail to the sender, delete it from your computer, and 
destroy any printed copy of it.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 4163 bytes
Desc: S/MIME Cryptographic Signature
URL: <http://lists.infradead.org/pipermail/linux-nvme/attachments/20210111/b0ccaeed/attachment.p7s>

From rach4x0r at gmail.com  Mon Jan 11 13:15:28 2021
From: rach4x0r at gmail.com (Rachit Agarwal)
Date: Mon, 11 Jan 2021 13:15:28 -0500
Subject: [PATCH] iosched: Add i10 I/O Scheduler
In-Reply-To: <CAKeUqKK3yykq8LNv1CCHZTHSz1=bzBaCwVQmi6bhpbYzqVJsqQ@mail.gmail.com>
References: <20201112140752.1554-1-rach4x0r@gmail.com>
 <5a954c4e-aa84-834d-7d04-0ce3545d45c9@kernel.dk>
 <da0c7aea-d917-4f3a-5136-89c30d12ba1f@grimberg.me>
 <fd12993a-bcb7-7b45-5406-61da1979d49d@kernel.dk>
 <10993ce4-7048-a369-ea44-adf445acfca7@grimberg.me>
 <c4cb66f6-8a66-7973-dc03-0f4f61d0a1e4@kernel.dk>
 <cbe18a3d-8a6b-e775-81bb-3b3f11045183@grimberg.me>
 <26a1cd20-6b25-eaa6-7ab6-ba7f5afaf6dd@kernel.dk>
 <81cdcb58-9a23-8192-6213-7f2408a3b8ee@grimberg.me>
 <CAKeUqKKHg1wD19pnwJEd8whubnuGVic_ZhDjebaq3kKmY9TtsQ@mail.gmail.com>
 <CAKeUqKK3yykq8LNv1CCHZTHSz1=bzBaCwVQmi6bhpbYzqVJsqQ@mail.gmail.com>
Message-ID: <CAKeUqKJKXP8iJY1x=wXc7Vz+qQPhP=MaUmy71x2f2H_YdHf_8w@mail.gmail.com>

[Resending the last message] Happy 2021 everyone!

> Dear all:
>
> Hope you are all well.
>
> Sagi and I were wondering if you have any additional feedback on the
> updated patch? (@Ming?) We have been receiving a lot of
> interest/questions from industry on incorporation of i10 in the
> kernel. If people do not have additional feedback, it would be nice to
> move this forward.
>
> Looking forward to hearing from you!
> ~Rachit
>
> On Sat, Nov 28, 2020 at 12:49 AM Rachit Agarwal <rach4x0r at gmail.com> wrote:
> >
> >
> >
> > On Fri, Nov 13, 2020 at 4:56 PM Sagi Grimberg <sagi at grimberg.me> wrote:
> >>
> >>
> >> >>>> But if you think this has a better home, I'm assuming that the guys
> >> >>>> will be open to that.
> >> >>>
> >> >>> Also see the reply from Ming. It's a balancing act - don't want to add
> >> >>> extra overhead to the core, but also don't want to carry an extra
> >> >>> scheduler if the main change is really just variable dispatch batching.
> >> >>> And since we already have a notion of that, seems worthwhile to explore
> >> >>> that venue.
> >> >>
> >> >> I agree,
> >> >>
> >> >> The main difference is that this balancing is not driven from device
> >> >> resource pressure, but rather from an assumption of device specific
> >> >> optimization (and also with a specific optimization target), hence a
> >> >> scheduler a user would need to opt-in seemed like a good compromise.
> >> >>
> >> >> But maybe Ming has some good ideas on a different way to add it..
> >> >
> >> > So here's another case - virtualized nvme. The commit overhead is
> >> > suitably large there that performance suffers quite a bit, similarly to
> >> > your remote storage case. If we had suitable logic in the core, then we
> >> > could easily propagate this knowledge when setting up the queue. Then it
> >> > could happen automatically, without needing a configuration to switch to
> >> > a specific scheduler.
> >>
> >> Yes, these use-cases share characteristics. I'm not at all opposed to
> >> placing this in the core. I do think that in order to put something like
> >> this in the core, the bar needs to be higher such that an optimization
> >> target cannot be biased towards a workload (i.e. needs to be adaptive).
> >>
> >> I'm still not sure how we would build this on top of what we already
> >> have as it is really centered around device being busy (which is not
> >> the case for nvme), but I didn't put enough thought into it yet.
> >>
> >
> > Dear all:
> >
> > Thanks, again, for the very constructive decisions.
> >
> > I am writing back with quite a few updates:
> >
> > 1. We have now included a detailed comparison of i10 scheduler with Kyber with NVMe-over-TCP (https://github.com/i10-kernel/upstream-linux/blob/master/i10-evaluation.pdf). In a nutshell, when operating with NVMe-over-TCP, i10 demonstrates the core tradeoff: higher latency, but also higher throughput. This seems to be the core tradeoff exposed by i10.
> >
> > 2. We have now implemented an adaptive version of i10 I/O scheduler, that uses the number of outstanding requests at the time of batch dispatch (and whether the dispatch was triggered by timeout or not) to adaptively set the batching size. The new results (https://github.com/i10-kernel/upstream-linux/blob/master/i10-evaluation.pdf) show that i10-adaptive further improves performance for low loads, while keeping the performance for high loads. IMO, there is much to do on designing improved adaptation algorithms.
> >
> > 3. We have now updated the i10-evaluation document to include results for local storage access. The core take-away here is that i10-adaptive can achieve similar throughput and latency at low loads and at high loads when compared to noop, but still requires more work for lower loads. However, given that the tradeoff exposed by i10 scheduler is particularly useful for remote storage devices (and as Jens suggested, perhaps for virtualized local storage access), I do agree with Sagi -- I think we should consider including it in the core, since this may be useful for a broad range of new use cases.
> >
> > We have also created a second version of the patch that includes these updates: https://github.com/i10-kernel/upstream-linux/blob/master/0002-iosched-Add-i10-I-O-Scheduler.patch
> >
> > As always, thank you for the constructive discussion and I look forward to working with you on this.
> >
> > Best,
> > ~Rachit
> >


From javier at javigon.com  Mon Jan 11 13:53:47 2021
From: javier at javigon.com (Javier =?utf-8?B?R29uesOhbGV6?=)
Date: Mon, 11 Jan 2021 19:53:47 +0100
Subject: nvme: enable char device per namespace
In-Reply-To: <20201216181828.21040-1-javier.gonz@samsung.com>
References: <CGME20201216181838eucas1p15c687e5d1319d3fa581990e6cca73295@eucas1p1.samsung.com>
 <20201216181828.21040-1-javier.gonz@samsung.com>
Message-ID: <20210111185347.oqqzdmoglg3lzo5y@mpHalley.localdomain>

On 16.12.2020 19:18, javier at javigon.com wrote:
>From: Javier Gonz?lez <javier.gonz at samsung.com>
>
>Create a char device per NVMe namespace. This char device is always
>initialized, independently of whether the features implemented by the
>device are supported by the kernel. User-space can therefore always
>issue IOCTLs to the NVMe driver using the char device.
>
>The char device is presented as /dev/generic-nvmeXcYnZ. This naming
>scheme follows the convention of the hidden device (nvmeXcYnZ). Support
>for multipath will follow.
>
>Keith: Regarding nvme-cli support, should the generic handle show up in
>place such as 'nvme list'? If so, I can send a patch for the filters.
>
>Changes since V3 (merged patch from keith)
>  - Use a dedicated ida for the generic handle
>  - Do not abort namespace greation if the generic handle fails
>
>Changes since V2:
>  - Apply a number of naming and code structure improvements (from
>    Christoph)
>  - Use i_cdev to pull struct nvme_ns in the ioctl path instead of
>    populating file->private_data (from Christoph)
>  - Change char device and sysfs entries to /dev/generic-nvmeXcYnZ to
>    follow the hidden device naming scheme (from Christoph and Keith)
>
>Changes since V1:
>  - Remove patches 1-3 which are already picked up by Christoph
>  - Change the char device and sysfs entries to nvmeXnYc / c signals
>    char device
>  - Address Minwoo's comments on inline functions and style
>
>Signed-off-by: Javier Gonz?lez <javier.gonz at samsung.com>
>---
> drivers/nvme/host/core.c | 159 +++++++++++++++++++++++++++++++++++----
> drivers/nvme/host/nvme.h |   9 +++
> 2 files changed, 152 insertions(+), 16 deletions(-)
>
>diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
>index 99f91efe3824..d1ee462f41fa 100644
>--- a/drivers/nvme/host/core.c
>+++ b/drivers/nvme/host/core.c
>@@ -86,7 +86,11 @@ static DEFINE_MUTEX(nvme_subsystems_lock);
>
> static DEFINE_IDA(nvme_instance_ida);
> static dev_t nvme_ctrl_base_chr_devt;
>+
>+static DEFINE_IDA(nvme_gen_minor_ida);
>+static dev_t nvme_ns_base_chr_devt;
> static struct class *nvme_class;
>+static struct class *nvme_ns_class;
> static struct class *nvme_subsys_class;
>
> static void nvme_put_subsystem(struct nvme_subsystem *subsys);
>@@ -537,7 +541,10 @@ static void nvme_free_ns(struct kref *kref)
>
> 	if (ns->ndev)
> 		nvme_nvm_unregister(ns);
>+	if (ns->minor)
>+		ida_simple_remove(&nvme_gen_minor_ida, ns->minor - 1);
>
>+	cdev_device_del(&ns->cdev, &ns->cdev_device);
> 	put_disk(ns->disk);
> 	nvme_put_ns_head(ns->head);
> 	nvme_put_ctrl(ns->ctrl);
>@@ -1738,15 +1745,15 @@ static int nvme_handle_ctrl_ioctl(struct nvme_ns *ns, unsigned int cmd,
> 	return ret;
> }
>
>-static int nvme_ioctl(struct block_device *bdev, fmode_t mode,
>-		unsigned int cmd, unsigned long arg)
>+static int nvme_disk_ioctl(struct gendisk *disk, unsigned int cmd,
>+			   unsigned long arg)
> {
> 	struct nvme_ns_head *head = NULL;
> 	void __user *argp = (void __user *)arg;
> 	struct nvme_ns *ns;
> 	int srcu_idx, ret;
>
>-	ns = nvme_get_ns_from_disk(bdev->bd_disk, &head, &srcu_idx);
>+	ns = nvme_get_ns_from_disk(disk, &head, &srcu_idx);
> 	if (unlikely(!ns))
> 		return -EWOULDBLOCK;
>
>@@ -1783,6 +1790,12 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode,
> 	return ret;
> }
>
>+static int nvme_ioctl(struct block_device *bdev, fmode_t mode,
>+		      unsigned int cmd, unsigned long arg)
>+{
>+	return nvme_disk_ioctl(bdev->bd_disk, cmd, arg);
>+}
>+
> #ifdef CONFIG_COMPAT
> struct nvme_user_io32 {
> 	__u8	opcode;
>@@ -1824,10 +1837,8 @@ static int nvme_compat_ioctl(struct block_device *bdev, fmode_t mode,
> #define nvme_compat_ioctl	NULL
> #endif /* CONFIG_COMPAT */
>
>-static int nvme_open(struct block_device *bdev, fmode_t mode)
>+static int nvme_ns_open(struct nvme_ns *ns)
> {
>-	struct nvme_ns *ns = bdev->bd_disk->private_data;
>-
> #ifdef CONFIG_NVME_MULTIPATH
> 	/* should never be called due to GENHD_FL_HIDDEN */
> 	if (WARN_ON_ONCE(ns->head->disk))
>@@ -1846,14 +1857,22 @@ static int nvme_open(struct block_device *bdev, fmode_t mode)
> 	return -ENXIO;
> }
>
>-static void nvme_release(struct gendisk *disk, fmode_t mode)
>+static void nvme_ns_release(struct nvme_ns *ns)
> {
>-	struct nvme_ns *ns = disk->private_data;
>-
> 	module_put(ns->ctrl->ops->module);
> 	nvme_put_ns(ns);
> }
>
>+static int nvme_open(struct block_device *bdev, fmode_t mode)
>+{
>+	return nvme_ns_open(bdev->bd_disk->private_data);
>+}
>+
>+static void nvme_release(struct gendisk *disk, fmode_t mode)
>+{
>+	nvme_ns_release(disk->private_data);
>+}
>+
> static int nvme_getgeo(struct block_device *bdev, struct hd_geometry *geo)
> {
> 	/* some standard values */
>@@ -2209,6 +2228,13 @@ static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_id_ns *id)
> 	return 0;
>
> out_unfreeze:
>+	/*
>+	 * When the device does not support any of the features required by the
>+	 * kernel (or viceversa), hide the block device. We can still rely on
>+	 * the namespace char device for submitting IOCTLs
>+	 */
>+	ns->disk->flags |= GENHD_FL_HIDDEN;
>+
> 	blk_mq_unfreeze_queue(ns->disk->queue);
> 	return ret;
> }
>@@ -2346,6 +2372,38 @@ static const struct block_device_operations nvme_bdev_ops = {
> 	.pr_ops		= &nvme_pr_ops,
> };
>
>+static int nvme_cdev_open(struct inode *inode, struct file *file)
>+{
>+	struct nvme_ns *ns = container_of(inode->i_cdev, struct nvme_ns, cdev);
>+
>+	return nvme_ns_open(ns);
>+}
>+
>+static int nvme_cdev_release(struct inode *inode, struct file *file)
>+{
>+	struct nvme_ns *ns = container_of(inode->i_cdev, struct nvme_ns, cdev);
>+
>+	nvme_ns_release(ns);
>+	return 0;
>+}
>+
>+static long nvme_cdev_ioctl(struct file *file, unsigned int cmd,
>+			    unsigned long arg)
>+{
>+	struct nvme_ns *ns = container_of(file->f_inode->i_cdev,
>+				struct nvme_ns, cdev);
>+
>+	return nvme_disk_ioctl(ns->disk, cmd, arg);
>+}
>+
>+static const struct file_operations nvme_cdev_fops = {
>+	.owner		= THIS_MODULE,
>+	.open		= nvme_cdev_open,
>+	.release	= nvme_cdev_release,
>+	.unlocked_ioctl	= nvme_cdev_ioctl,
>+	.compat_ioctl	= compat_ptr_ioctl,
>+};
>+
> #ifdef CONFIG_NVME_MULTIPATH
> static int nvme_ns_head_open(struct block_device *bdev, fmode_t mode)
> {
>@@ -3343,6 +3401,9 @@ static inline struct nvme_ns_head *dev_to_ns_head(struct device *dev)
> {
> 	struct gendisk *disk = dev_to_disk(dev);
>
>+	if (dev->class == nvme_ns_class)
>+		return nvme_get_ns_from_cdev(dev)->head;
>+
> 	if (disk->fops == &nvme_bdev_ops)
> 		return nvme_get_ns_from_dev(dev)->head;
> 	else
>@@ -3474,6 +3535,11 @@ const struct attribute_group *nvme_ns_id_attr_groups[] = {
> 	NULL,
> };
>
>+const struct attribute_group *nvme_ns_char_id_attr_groups[] = {
>+	&nvme_ns_id_attr_group,
>+	NULL,
>+};
>+
> #define nvme_show_str_function(field)						\
> static ssize_t  field##_show(struct device *dev,				\
> 			    struct device_attribute *attr, char *buf)		\
>@@ -3866,6 +3932,47 @@ struct nvme_ns *nvme_find_get_ns(struct nvme_ctrl *ctrl, unsigned nsid)
> }
> EXPORT_SYMBOL_NS_GPL(nvme_find_get_ns, NVME_TARGET_PASSTHRU);
>
>+static int nvme_alloc_chardev_ns(struct nvme_ctrl *ctrl, struct nvme_ns *ns)
>+{
>+	char cdisk_name[DISK_NAME_LEN];
>+	int ret;
>+
>+	ret = ida_simple_get(&nvme_gen_minor_ida, 0, 0, GFP_KERNEL);
>+	if (ret < 0)
>+		return ret;
>+
>+	ns->minor = ret + 1;
>+	device_initialize(&ns->cdev_device);
>+	ns->cdev_device.devt = MKDEV(MAJOR(nvme_ns_base_chr_devt), ret);
>+	ns->cdev_device.class = nvme_ns_class;
>+	ns->cdev_device.parent = ctrl->device;
>+	ns->cdev_device.groups = nvme_ns_char_id_attr_groups;
>+	dev_set_drvdata(&ns->cdev_device, ns);
>+
>+	sprintf(cdisk_name, "nvme-generic-%dc%dn%d", ctrl->subsys->instance,
>+		ctrl->instance, ns->head->instance);
>+
>+	ret = dev_set_name(&ns->cdev_device, "%s", cdisk_name);
>+	if (ret)
>+		goto put_ida;
>+
>+	cdev_init(&ns->cdev, &nvme_cdev_fops);
>+	ns->cdev.owner = ctrl->ops->module;
>+
>+	ret = cdev_device_add(&ns->cdev, &ns->cdev_device);
>+	if (ret)
>+		goto free_kobj;
>+
>+	return ret;
>+
>+free_kobj:
>+	kfree_const(ns->cdev_device.kobj.name);
>+put_ida:
>+	ida_simple_remove(&nvme_gen_minor_ida, ns->minor - 1);
>+	ns->minor = 0;
>+	return ret;
>+}
>+
> static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid,
> 		struct nvme_ns_ids *ids)
> {
>@@ -3912,8 +4019,7 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid,
> 	memcpy(disk->disk_name, disk_name, DISK_NAME_LEN);
> 	ns->disk = disk;
>
>-	if (nvme_update_ns_info(ns, id))
>-		goto out_put_disk;
>+	nvme_update_ns_info(ns, id);
>
> 	if ((ctrl->quirks & NVME_QUIRK_LIGHTNVM) && id->vs[0] == 0x1) {
> 		if (nvme_nvm_register(ns, disk_name, node)) {
>@@ -3929,9 +4035,14 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid,
> 	nvme_get_ctrl(ctrl);
>
> 	device_add_disk(ctrl->device, ns->disk, nvme_ns_id_attr_groups);
>-
> 	nvme_mpath_add_disk(ns, id);
> 	nvme_fault_inject_init(&ns->fault_inject, ns->disk->disk_name);
>+
>+	if (nvme_alloc_chardev_ns(ctrl, ns))
>+		dev_warn(ctrl->device,
>+			"failed to create generic handle for nsid:%d\n",
>+			nsid);
>+
> 	kfree(id);
>
> 	return;
>@@ -4733,23 +4844,38 @@ static int __init nvme_core_init(void)
> 	if (result < 0)
> 		goto destroy_delete_wq;
>
>+	result = alloc_chrdev_region(&nvme_ns_base_chr_devt, 0,
>+			NVME_MINORS, "nvmec");
>+	if (result < 0)
>+		goto unregister_dev_chrdev;
>+
> 	nvme_class = class_create(THIS_MODULE, "nvme");
> 	if (IS_ERR(nvme_class)) {
> 		result = PTR_ERR(nvme_class);
>-		goto unregister_chrdev;
>+		goto unregister_ns_chrdev;
> 	}
> 	nvme_class->dev_uevent = nvme_class_uevent;
>
>+	nvme_ns_class = class_create(THIS_MODULE, "nvme-ns");
>+	if (IS_ERR(nvme_ns_class)) {
>+		result = PTR_ERR(nvme_ns_class);
>+		goto destroy_dev_class;
>+	}
>+
> 	nvme_subsys_class = class_create(THIS_MODULE, "nvme-subsystem");
> 	if (IS_ERR(nvme_subsys_class)) {
> 		result = PTR_ERR(nvme_subsys_class);
>-		goto destroy_class;
>+		goto destroy_ns_class;
> 	}
> 	return 0;
>
>-destroy_class:
>+destroy_ns_class:
>+	class_destroy(nvme_ns_class);
>+destroy_dev_class:
> 	class_destroy(nvme_class);
>-unregister_chrdev:
>+unregister_ns_chrdev:
>+	unregister_chrdev_region(nvme_ns_base_chr_devt, NVME_MINORS);
>+unregister_dev_chrdev:
> 	unregister_chrdev_region(nvme_ctrl_base_chr_devt, NVME_MINORS);
> destroy_delete_wq:
> 	destroy_workqueue(nvme_delete_wq);
>@@ -4765,6 +4891,7 @@ static void __exit nvme_core_exit(void)
> {
> 	class_destroy(nvme_subsys_class);
> 	class_destroy(nvme_class);
>+	unregister_chrdev_region(nvme_ns_base_chr_devt, NVME_MINORS);
> 	unregister_chrdev_region(nvme_ctrl_base_chr_devt, NVME_MINORS);
> 	destroy_workqueue(nvme_delete_wq);
> 	destroy_workqueue(nvme_reset_wq);
>diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
>index bfcedfa4b057..1e52f7da82de 100644
>--- a/drivers/nvme/host/nvme.h
>+++ b/drivers/nvme/host/nvme.h
>@@ -439,6 +439,10 @@ struct nvme_ns {
> 	struct kref kref;
> 	struct nvme_ns_head *head;
>
>+	struct device cdev_device;	/* char device */
>+	struct cdev cdev;
>+	int minor;
>+
> 	int lba_shift;
> 	u16 ms;
> 	u16 sgs;
>@@ -818,6 +822,11 @@ static inline struct nvme_ns *nvme_get_ns_from_dev(struct device *dev)
> 	return dev_to_disk(dev)->private_data;
> }
>
>+static inline struct nvme_ns *nvme_get_ns_from_cdev(struct device *dev)
>+{
>+	return dev_get_drvdata(dev);
>+}
>+
> #ifdef CONFIG_NVME_HWMON
> int nvme_hwmon_init(struct nvme_ctrl *ctrl);
> #else
>-- 
>2.17.1
>
Christoph, Keith,

Did you have a chance to look into this new version?

Javier


From michal.krakowiak at linux.intel.com  Mon Jan 11 15:15:52 2021
From: michal.krakowiak at linux.intel.com (Michal Krakowiak)
Date: Mon, 11 Jan 2021 21:15:52 +0100
Subject: [PATCH] nvme: trace: parse format nvm command in detail
In-Reply-To: <20210111175018.GD1458209@dhcp-10-100-145-180.wdc.com>
References: <20210104155343.GA26034@michal-desk>
 <20210104160220.GB1024941@dhcp-10-100-145-180.wdc.com>
 <20210106090053.GA32643@lst.de>
 <20210108223431.GA1451691@dhcp-10-100-145-180.wdc.com>
 <CAPcyv4jLWOKDTyGzwar4C0H5euggvD_Ak6NESLd9=1THGC=ASg@mail.gmail.com>
 <20210111170110.GC1458209@dhcp-10-100-145-180.wdc.com>
 <CAPcyv4g3LKRmUOj1QHmkQ5rZ4BfH6TQaK6jKhXfb2DoBW-MoUQ@mail.gmail.com>
 <20210111175018.GD1458209@dhcp-10-100-145-180.wdc.com>
Message-ID: <20210111201552.GA90320@michal-desk>

On Mon, Jan 11, 2021 at 09:50:18AM -0800, Keith Busch wrote:
>On Mon, Jan 11, 2021 at 09:10:34AM -0800, Dan Williams wrote:
>> On Mon, Jan 11, 2021 at 9:01 AM Keith Busch <kbusch at kernel.org> wrote:
>> >
>> > On Fri, Jan 08, 2021 at 04:12:31PM -0800, Dan Williams wrote:
>> > > Is there a more centralized place to land such a helper? trace-cmd,
>> > > perf? The nice thing about kernel parsing is I don't need to have a
>> > > separate pile of disparate tools across subsystems.
>> >
>> > Yes, I just placed it in a temporary location to see if the other nvme
>> > stakeholders are okay with the idea. If so, I can make a real patch
>> > series to remove the in-kernel decoding, and add the parsing script
>> > somewhere in tools/.
>>
>> "Somewhere in tools/" is still not quite what I'm asking for, I want
>> something nearly as automatic and seamless as the kernel ftrace pipe.
>> If I need nvme tools for nvme events and mce tools for mce events etc,
>> I'd rather just have decode in the kernel. Perhaps this is a use case
>> for a usermode helper that accompanies a new kernel tracing file?. If
>> the helper exists the events supported events are decoded if the
>> helper is missing the interface is equivalent to the raw formatted
>> events. Decoded events "just work".
>
>My only concern is that decoding omits fields, so you have to ugprade
>your kernel in order to see the missing ones when the current kernel's
>decoding doesn't "just work". If that's how people want to maintain
>them, then I won't object any longer.

Like Dan, I really appreciate having the trace parsed in the kernel. I 
understand the concerns. What about having both: detailed parsing and 
raw bytes? It does not seem to me like a big deal to append a field with 
the raw data even if detailed parsing is implemented. Let the parsing 
extends the raw data instead of replacing them. This will result in the 
detailed human-friendly output (which is nice to have) while not losing 
data in the future (in the case that a new unsupported by parser field 
appears).


From james.smart at broadcom.com  Mon Jan 11 18:46:20 2021
From: james.smart at broadcom.com (James Smart)
Date: Mon, 11 Jan 2021 15:46:20 -0800
Subject: [PATCH v2] nvmet-fc: associations list protected by rcu, instead
 of spinlock_irq where possible.
In-Reply-To: <1609697575-103348-2-git-send-email-leonid.ravich@dell.com>
References: <20201224110542.22219-1-leonid.ravich@dell.com>
 <1609697575-103348-1-git-send-email-leonid.ravich@dell.com>
 <1609697575-103348-2-git-send-email-leonid.ravich@dell.com>
Message-ID: <2d7f5b89-f8a2-f80f-cf8e-d7dc0470acca@broadcom.com>



On 1/3/2021 10:12 AM, leonid.ravich at dell.com wrote:
> From: Leonid Ravich <Leonid.Ravich at emc.com>
>
> searching assoc_list protected by rcu_read_lock if list not changed inline.
> and according to the rcu list rules.
>
> queue array embedded into nvmet_fc_tgt_assoc protected by rcu_read_lock
> according to rcu dereference/assign rules.
>
> queue and assoc object freed after grace period by call_rcu.
>
> tgtport lock taken for changing assoc_list.
>
> Reviewed-by: Eldad Zinger <Eldad.Zinger at dell.com>
> Reviewed-by: Elad Grupi <Elad.Grupi at dell.com>
> Signed-off-by: Leonid Ravich <Leonid.Ravich at emc.com>
> ---
> 1) fixed sytle issus
> 2) queues array protects by rcu as well
>
>   drivers/nvme/target/fc.c | 81 +++++++++++++++++++++++-------------------------
>   1 file changed, 38 insertions(+), 43 deletions(-)
>
>

Reviewed-by: James Smart <james.smart at broadcom.com>

-- james

-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 4163 bytes
Desc: S/MIME Cryptographic Signature
URL: <http://lists.infradead.org/pipermail/linux-nvme/attachments/20210111/de8bec91/attachment-0001.p7s>

From sagi at grimberg.me  Mon Jan 11 19:36:33 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Mon, 11 Jan 2021 16:36:33 -0800
Subject: Data corruption when using multiple devices with NVMEoF TCP
In-Reply-To: <CAJS6Edi9Es1zR9QC+=kwVjAFAGYrEru4vibW42ffyWoMDutFhQ@mail.gmail.com>
References: <CAJS6EdjsTVgs3JK3q2DePjEz1A0s9RJTOwqo=Ka7kinNMECtJw@mail.gmail.com>
 <2c0ff5ec-4ae2-ad29-67fb-4744514dab47@grimberg.me>
 <CAJS6Edh8aVAHhKRGqU+7v5C3KY7YxczVg_7Q8QrPGtyvVw7K3w@mail.gmail.com>
 <fd4541e4-78c5-ec3b-b272-467fd11f7472@grimberg.me>
 <20201223084332.GA30502@infradead.org>
 <CAJS6EdijX6ws_wHxygdpcYGtB6JFwLDbDE3A0t0QUYS-LbRakg@mail.gmail.com>
 <16d876c1-524a-38d3-3cff-99ec694464b2@grimberg.me>
 <CAJS6EdivEF0c=3FmKj4wGZoVRKbUvjH_qJLXmO7Tvwsp+km0rw@mail.gmail.com>
 <f631893c-5ce9-95fd-c32c-35a7e70d093c@grimberg.me>
 <CAJS6EdjUAb77-rWd=XmFhsM2_3Hds6VV6jQUVPJoJQHhk12J_Q@mail.gmail.com>
 <a6564a08-a3b0-5c22-51e3-712c4714bcc5@grimberg.me>
 <CAJS6Edgb+yCW5q5dA=MEkL0eYs4MXoopdiz72nhkxpkd5Fe_cA@mail.gmail.com>
 <ae5b1654-e580-88be-0498-0cd111b53fa2@grimberg.me>
 <CAJS6Edjkfvs4pfH9XvwAT0h4STuoDh1PahSxkkTWOsKwgL5pZQ@mail.gmail.com>
 <16fe1e9c-3a43-ef28-7b69-755e6a86464f@grimberg.me>
 <CAJS6Edi9Es1zR9QC+=kwVjAFAGYrEru4vibW42ffyWoMDutFhQ@mail.gmail.com>
Message-ID: <4684c86a-8cc7-c5ae-0d6b-9f0e7c59eda5@grimberg.me>

Hey Hao,

> Here is the entire log (and it's a new one, i.e. above snippet not 
> included):
> https://drive.google.com/file/d/16ArIs5-Jw4P2f17A_ftKLm1A4LQUFpmg/view?usp=sharing
> 
> What I found is the data corruption does not always happen, especially 
> when I copy a small directory. So I guess a lot of log entries should 
> just look fine.

So this seems to be a breakage that existed for some time now with
multipage bvecs that you have been the first one to report. This
seems to be related to bio merges, which is seems strange to me
why this just now comes up, perhaps it is the combination with
raid0 that triggers this, I'm not sure.

IIUC, this should resolve your issue, care to give it a go?
--
diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 973d5d683180..6bceadc204a8 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -201,8 +201,9 @@ static inline size_t nvme_tcp_req_cur_offset(struct 
nvme_tcp_request *req)

  static inline size_t nvme_tcp_req_cur_length(struct nvme_tcp_request *req)
  {
-       return min_t(size_t, req->iter.bvec->bv_len - req->iter.iov_offset,
-                       req->pdu_len - req->pdu_sent);
+       return min_t(size_t, req->iter.count,
+                       min_t(size_t, req->iter.bvec->bv_len - 
req->iter.iov_offset,
+                               req->pdu_len - req->pdu_sent));
  }

  static inline size_t nvme_tcp_pdu_data_left(struct nvme_tcp_request *req)
@@ -223,7 +224,7 @@ static void nvme_tcp_init_iter(struct 
nvme_tcp_request *req,
         struct request *rq = blk_mq_rq_from_pdu(req);
         struct bio_vec *vec;
         unsigned int size;
-       int nsegs;
+       int nsegs = 0;
         size_t offset;

         if (rq->rq_flags & RQF_SPECIAL_PAYLOAD) {
@@ -233,11 +234,15 @@ static void nvme_tcp_init_iter(struct 
nvme_tcp_request *req,
                 offset = 0;
         } else {
                 struct bio *bio = req->curr_bio;
+               struct bvec_iter bi;
+               struct bio_vec bv;

                 vec = __bvec_iter_bvec(bio->bi_io_vec, bio->bi_iter);
-               nsegs = bio_segments(bio);
+               bio_for_each_bvec(bv, bio, bi) {
+                       nsegs++;
+               }
                 size = bio->bi_iter.bi_size;
-               offset = bio->bi_iter.bi_bvec_done;
+               offset = mp_bvec_iter_offset(bio->bi_io_vec, 
bio->bi_iter) - vec->bv_offset;
         }

         iov_iter_bvec(&req->iter, dir, vec, nsegs, size);
--


From sagi at grimberg.me  Mon Jan 11 20:29:37 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Mon, 11 Jan 2021 17:29:37 -0800
Subject: Data corruption when using multiple devices with NVMEoF TCP
In-Reply-To: <4684c86a-8cc7-c5ae-0d6b-9f0e7c59eda5@grimberg.me>
References: <CAJS6EdjsTVgs3JK3q2DePjEz1A0s9RJTOwqo=Ka7kinNMECtJw@mail.gmail.com>
 <CAJS6Edh8aVAHhKRGqU+7v5C3KY7YxczVg_7Q8QrPGtyvVw7K3w@mail.gmail.com>
 <fd4541e4-78c5-ec3b-b272-467fd11f7472@grimberg.me>
 <20201223084332.GA30502@infradead.org>
 <CAJS6EdijX6ws_wHxygdpcYGtB6JFwLDbDE3A0t0QUYS-LbRakg@mail.gmail.com>
 <16d876c1-524a-38d3-3cff-99ec694464b2@grimberg.me>
 <CAJS6EdivEF0c=3FmKj4wGZoVRKbUvjH_qJLXmO7Tvwsp+km0rw@mail.gmail.com>
 <f631893c-5ce9-95fd-c32c-35a7e70d093c@grimberg.me>
 <CAJS6EdjUAb77-rWd=XmFhsM2_3Hds6VV6jQUVPJoJQHhk12J_Q@mail.gmail.com>
 <a6564a08-a3b0-5c22-51e3-712c4714bcc5@grimberg.me>
 <CAJS6Edgb+yCW5q5dA=MEkL0eYs4MXoopdiz72nhkxpkd5Fe_cA@mail.gmail.com>
 <ae5b1654-e580-88be-0498-0cd111b53fa2@grimberg.me>
 <CAJS6Edjkfvs4pfH9XvwAT0h4STuoDh1PahSxkkTWOsKwgL5pZQ@mail.gmail.com>
 <16fe1e9c-3a43-ef28-7b69-755e6a86464f@grimberg.me>
 <CAJS6Edi9Es1zR9QC+=kwVjAFAGYrEru4vibW42ffyWoMDutFhQ@mail.gmail.com>
 <4684c86a-8cc7-c5ae-0d6b-9f0e7c59eda5@grimberg.me>
Message-ID: <fcb56817-1f34-e307-e888-45ebb661c31d@grimberg.me>


> Hey Hao,
> 
>> Here is the entire log (and it's a new one, i.e. above snippet not 
>> included):
>> https://drive.google.com/file/d/16ArIs5-Jw4P2f17A_ftKLm1A4LQUFpmg/view?usp=sharing 
>>
>>
>> What I found is the data corruption does not always happen, especially 
>> when I copy a small directory. So I guess a lot of log entries should 
>> just look fine.
> 
> So this seems to be a breakage that existed for some time now with
> multipage bvecs that you have been the first one to report. This
> seems to be related to bio merges, which is seems strange to me
> why this just now comes up, perhaps it is the combination with
> raid0 that triggers this, I'm not sure.

OK, I think I understand what is going on. With multipage bvecs
bios can split in the middle of a bvec entry, and then merge
back with another bio.

The issue is that we are not capping the last bvec entry send length
calculation in that.

I think that just this can also resolve the issue:
--
diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 973d5d683180..c6b0a189a494 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -201,8 +201,9 @@ static inline size_t nvme_tcp_req_cur_offset(struct 
nvme_tcp_request *req)

  static inline size_t nvme_tcp_req_cur_length(struct nvme_tcp_request *req)
  {
-       return min_t(size_t, req->iter.bvec->bv_len - req->iter.iov_offset,
-                       req->pdu_len - req->pdu_sent);
+       return min_t(size_t, req->iter.count,
+                       min_t(size_t, req->iter.bvec->bv_len - 
req->iter.iov_offset,
+                               req->pdu_len - req->pdu_sent));
  }

  static inline size_t nvme_tcp_pdu_data_left(struct nvme_tcp_request *req)
--


From tom.leiming at gmail.com  Mon Jan 11 21:22:05 2021
From: tom.leiming at gmail.com (Ming Lei)
Date: Tue, 12 Jan 2021 10:22:05 +0800
Subject: Data corruption when using multiple devices with NVMEoF TCP
In-Reply-To: <fcb56817-1f34-e307-e888-45ebb661c31d@grimberg.me>
References: <CAJS6EdjsTVgs3JK3q2DePjEz1A0s9RJTOwqo=Ka7kinNMECtJw@mail.gmail.com>
 <CAJS6Edh8aVAHhKRGqU+7v5C3KY7YxczVg_7Q8QrPGtyvVw7K3w@mail.gmail.com>
 <fd4541e4-78c5-ec3b-b272-467fd11f7472@grimberg.me>
 <20201223084332.GA30502@infradead.org>
 <CAJS6EdijX6ws_wHxygdpcYGtB6JFwLDbDE3A0t0QUYS-LbRakg@mail.gmail.com>
 <16d876c1-524a-38d3-3cff-99ec694464b2@grimberg.me>
 <CAJS6EdivEF0c=3FmKj4wGZoVRKbUvjH_qJLXmO7Tvwsp+km0rw@mail.gmail.com>
 <f631893c-5ce9-95fd-c32c-35a7e70d093c@grimberg.me>
 <CAJS6EdjUAb77-rWd=XmFhsM2_3Hds6VV6jQUVPJoJQHhk12J_Q@mail.gmail.com>
 <a6564a08-a3b0-5c22-51e3-712c4714bcc5@grimberg.me>
 <CAJS6Edgb+yCW5q5dA=MEkL0eYs4MXoopdiz72nhkxpkd5Fe_cA@mail.gmail.com>
 <ae5b1654-e580-88be-0498-0cd111b53fa2@grimberg.me>
 <CAJS6Edjkfvs4pfH9XvwAT0h4STuoDh1PahSxkkTWOsKwgL5pZQ@mail.gmail.com>
 <16fe1e9c-3a43-ef28-7b69-755e6a86464f@grimberg.me>
 <CAJS6Edi9Es1zR9QC+=kwVjAFAGYrEru4vibW42ffyWoMDutFhQ@mail.gmail.com>
 <4684c86a-8cc7-c5ae-0d6b-9f0e7c59eda5@grimberg.me>
 <fcb56817-1f34-e307-e888-45ebb661c31d@grimberg.me>
Message-ID: <CACVXFVNwhFTq2Aq7bx7cwmhab4itkAntF-TKunv59XoZySy51w@mail.gmail.com>

On Tue, Jan 12, 2021 at 9:33 AM Sagi Grimberg <sagi at grimberg.me> wrote:
>
>
> > Hey Hao,
> >
> >> Here is the entire log (and it's a new one, i.e. above snippet not
> >> included):
> >> https://drive.google.com/file/d/16ArIs5-Jw4P2f17A_ftKLm1A4LQUFpmg/view?usp=sharing
> >>
> >>
> >> What I found is the data corruption does not always happen, especially
> >> when I copy a small directory. So I guess a lot of log entries should
> >> just look fine.
> >
> > So this seems to be a breakage that existed for some time now with
> > multipage bvecs that you have been the first one to report. This
> > seems to be related to bio merges, which is seems strange to me
> > why this just now comes up, perhaps it is the combination with
> > raid0 that triggers this, I'm not sure.
>
> OK, I think I understand what is going on. With multipage bvecs
> bios can split in the middle of a bvec entry, and then merge
> back with another bio.

IMO, bio split can be done in the middle of a bvec even though the bvec
is single page. The split may just be triggered in case of raid over nvme-tcp,
and I guess it might be triggered by device mapper too.


Thanks,
Ming


From chaitanya.kulkarni at wdc.com  Mon Jan 11 23:26:14 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Mon, 11 Jan 2021 20:26:14 -0800
Subject: [PATCH V9 0/9] nvmet: add ZBD backend support
Message-ID: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>

Hi,

NVMeOF Host is capable of handling the NVMe Protocol based Zoned Block
Devices (ZBD) in the Zoned Namespaces (ZNS) mode with the passthru
backend. There is no support for a generic block device backend to
handle the ZBD devices which are not NVMe protocol compliant.

This adds support to export the ZBDs (which are not NVMe drives) to host
the from target via NVMeOF using the host side ZNS interface.

The patch series is generated in bottom-top manner where, it first adds
prep patch and ZNS command-specific handlers on the top of genblk and 
updates the data structures, then one by one it wires up the admin cmds
in the order host calls them in namespace initializing sequence. Once
everything is ready, it wires-up the I/O command handlers. See below for
patch-series overview.

All the testcases are passing for the ZoneFS where ZBD exported with
NVMeOF backed by null_blk ZBD and null_blk ZBD without NVMeOF. Adding
test result below.

Note: This patch-series is based on the earlier posted patch series :-

[PATCH V2 0/4] nvmet: admin-cmd related cleanups and a fix
http://lists.infradead.org/pipermail/linux-nvme/2021-January/021729.html

-ck

Changes from V8:-

1. Rebase and retest on latest nvme-5.11.
2. Export ctrl->cap csi support only if CONFIG_BLK_DEV_ZONE is set.
3. Add a fix to admin ns-desc list handler for handling default csi.

Changes from V7:-

1. Just like what block layer provides an API for bio_init(), provide
   nvmet_bio_init() such that we move bio initialization code for
   nvme-read-write commands from bdev and zns backend into the centralize
   helper. 
2. With bdev/zns/file now we have three backends that are checking for
   req->sg_cnt and calling nvmet_check_transfer_len() before we process
   nvme-read-write commands. Move this duplicate code from three
   backeneds into the helper.
3. Export and use nvmet_bio_done() callback in
   nvmet_execute_zone_append() instead of the open coding the function.
   This also avoids code duplication for bio & request completion with
   error log page update.
4. Add zonefs tests log for dm linear device created on the top of SMR HDD
   exported with NVMeOF ZNS backend with the help of nvme-loop.

Changes from V6:-

1. Instead of calling report zones to find conventional zones in the 
   loop use the loop inside LLD blkdev_report_zones()->LLD_report_zones,
   that also simplifies the report zone callback.
2. Fix the bug in nvmet_bdev_has_conv_zones().
3. Remove conditional operators in the nvmet_bdev_execute_zone_append().

Changes from V5:-

1.  Use bio->bi_iter.bi_sector for result of the REQ_OP_ZONE_APPEND
    command.
2.  Add endianness to the helper nvmet_sect_to_lba().
3.  Make bufsize u32 in zone mgmt recv command handler.
4.  Add __GFP_ZERO for report zone data buffer to return clean buffer.

Changes from V4:-

1.  Don't use bio_iov_iter_get_pages() instead add a patch to export
    bio_add_hw_page() and call it directly for zone append.
2.  Add inline vector optimization for append bio.
3.  Update the commit logs for the patches.
4.  Remove ZNS related identify data structures, use individual members.
5.  Add a comment for macro NVMET_MPSMIN_SHIFT.
6.  Remove nvmet_bdev() helper.
7.  Move the command set identifier code into common code.
8.  Use IS_ENABLED() and move helpers fomr zns.c into common code.
9.  Add a patch to support Command Set identifiers.
10. Open code nvmet_bdev_validate_zns_zones().
11. Remove the per namespace min zasl calculation and don't allow
    namespaces with zasl value > the first ns zasl value.
12. Move the stubs into the header file.
13. Add lba to/from sector conversion helpers and update the
    io-cmd-bdev.c to avoid the code duplication.
14. Add everything into one patch for zns command handlers and 
    respective calls from the target code.
15. Remove the trim ns-desclist admin callback patch from this series.
16. Add bio get and put helpers patches to reduce the duplicate code in
    generic bdev, passthru, and generic zns backend.

Changes from V3:-

1.  Get rid of the bio_max_zasl check.
2.  Remove extra lines.
4.  Remove the block layer api export patch.
5.  Remove the bvec check in the bio_iov_iter_get_pages() for
    REQ_OP_ZONE_APPEND so that we can reuse the code.

Changes from V2:-

1.  Move conventional zone bitmap check into 
    nvmet_bdev_validate_zns_zones(). 
2.  Don't use report zones call to check the runt zone.
3.  Trim nvmet_zasl() helper.
4.  Fix typo in the nvmet_zns_update_zasl().
5.  Remove the comment and fix the mdts calculation in
    nvmet_execute_identify_cns_cs_ctrl().
6.  Use u64 for bufsize in nvmet_bdev_execute_zone_mgmt_recv().
7.  Remove nvmet_zones_to_desc_size() and fix the nr_zones
    calculation.
8.  Remove the op variable in nvmet_bdev_execute_zone_append().
9.  Fix the nr_zones calculation nvmet_bdev_execute_zone_mgmt_recv().
10. Update cover letter subject.

Changes from V1:-

1.  Remove the nvmet-$(CONFIG_BLK_DEV_ZONED) += zns.o.
2.  Mark helpers inline.
3.  Fix typos in the comments and update the comments.
4.  Get rid of the curly brackets.
5.  Don't allow drives with last smaller zones.
6.  Calculate the zasl as a function of ax_zone_append_sectors,
    bio_max_pages so we don't have to split the bio.
7.  Add global subsys->zasl and update the zasl when new namespace
    is enabled.
8.  Rmove the loop in the nvmet_bdev_execute_zone_mgmt_recv() and
    move functionality in to the report zone callback.
9.  Add goto for default case in nvmet_bdev_execute_zone_mgmt_send().
10. Allocate the zones buffer with zones size instead of bdev nr_zones.

Chaitanya Kulkarni (9):
  block: export bio_add_hw_pages()
  nvmet: add lba to sect conversion helpers
  nvmet: add NVM command set identifier support
  nvmet: add ZBD over ZNS backend support
  nvmet: add bio get helper for different backends
  nvmet: add bio init helper for different backends
  nvmet: add bio put helper for different backends
  nvmet: add common I/O length check helper
  nvmet: call nvmet_bio_done() for zone append

 block/bio.c                       |   1 +
 block/blk.h                       |   4 -
 drivers/nvme/target/Makefile      |   1 +
 drivers/nvme/target/admin-cmd.c   |  67 ++++--
 drivers/nvme/target/core.c        |  16 +-
 drivers/nvme/target/io-cmd-bdev.c |  67 +++---
 drivers/nvme/target/io-cmd-file.c |   7 +-
 drivers/nvme/target/nvmet.h       |  97 +++++++++
 drivers/nvme/target/passthru.c    |  11 +-
 drivers/nvme/target/zns.c         | 328 ++++++++++++++++++++++++++++++
 include/linux/blkdev.h            |   4 +
 11 files changed, 536 insertions(+), 67 deletions(-)
 create mode 100644 drivers/nvme/target/zns.c

* Zonefs Test log with dm-linear on the top of SMR HDD:-
--------------------------------------------------------------------------------

1. Test Zoned Block Device info :- 
--------------------------------------------------------------------------------

# fdisk  -l /dev/sdh
Disk /dev/sdh: 13.64 TiB, 15000173281280 bytes, 3662151680 sectors
Disk model: HGST HSH721415AL
Units: sectors of 1 * 4096 = 4096 bytes
Sector size (logical/physical): 4096 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
# cat /sys/block/sdh/queue/nr_zones
55880
# cat /sys/block/sdh/queue/zoned
host-managed
# cat /sys/block/sdh/queue/zone_append_max_bytes
688128

2. Creating NVMeOF target backed by dm-linear on the top of ZBD
--------------------------------------------------------------------------------

# ./zbdev.sh 1 dm-zbd
++ NQN=dm-zbd
++ echo '0 29022486528 linear /dev/sdh 274726912' | dmsetup create cksdh
9 directories, 4 files
++ mkdir /sys/kernel/config/nvmet/subsystems/dm-zbd
++ mkdir /sys/kernel/config/nvmet/subsystems/dm-zbd/namespaces/1
++ echo -n /dev/dm-0
++ cat /sys/kernel/config/nvmet/subsystems/dm-zbd/namespaces/1/device_path
/dev/dm-0
++ echo 1
++ mkdir /sys/kernel/config/nvmet/ports/1/
++ echo -n loop
++ echo -n 1
++ ln -s /sys/kernel/config/nvmet/subsystems/dm-zbd /sys/kernel/config/nvmet/ports/1/subsystems/
++ sleep 1
++ echo transport=loop,nqn=dm-zbd
++ sleep 1
++ dmesg -c
[233450.572565] nvmet: adding nsid 1 to subsystem dm-zbd
[233452.269477] nvmet: creating controller 1 for subsystem dm-zbd for NQN nqn.2014-08.org.nvmexpress:uuid:853d7e82-8018-44ce-8784-ab81e7465ad9.
[233452.283352] nvme nvme0: Please enable CONFIG_NVME_MULTIPATH for full support of multi-port devices.
[233452.292805] nvme nvme0: creating 8 I/O queues.
[233452.299210] nvme nvme0: new ctrl: "dm-zbd"

3. dm-linear and backend SMR HDD association :-
--------------------------------------------------------------------------------

# cat /sys/kernel/config/nvmet/subsystems/dm-zbd/namespaces/1/device_path 
/dev/dm-0
# dmsetup ls --tree
 cksdh (252:0)
	 ?? (8:112)
# lsblk | head -3
NAME    MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sdh       8:112  0  13.6T  0 disk 
??cksdh 252:0    0  13.5T  0 dm   

4. NVMeOF controller :- 
--------------------------------------------------------------------------------

# nvme list | tr -s ' ' ' '  
Node SN Model Namespace Usage Format FW Rev  
/dev/nvme0n1 8c6f348dcd64404c Linux 1 14.86 TB / 14.86 TB 4 KiB + 0 B 5.10.0nv

5. Zonefs tests results :-
--------------------------------------------------------------------------------

# ./zonefs-tests.sh /dev/nvme0n1 
Gathering information on /dev/nvme0n1...
zonefs-tests on /dev/nvme0n1:
  55356 zones (0 conventional zones, 55356 sequential zones)
  524288 512B sectors zone size (256 MiB)
  1 max open zones
Running tests
  Test 0010:  mkzonefs (options)                                   ... PASS
  Test 0011:  mkzonefs (force format)                              ... PASS
  Test 0012:  mkzonefs (invalid device)                            ... PASS
  Test 0013:  mkzonefs (super block zone state)                    ... PASS
  Test 0020:  mount (default)                                      ... PASS
  Test 0021:  mount (invalid device)                               ... PASS
  Test 0022:  mount (check mount directory sub-directories)        ... PASS
  Test 0023:  mount (options)                                      ... PASS
  Test 0030:  Number of files (default)                            ... PASS
  Test 0031:  Number of files (aggr_cnv)                           ... skip
  Test 0032:  Number of files using stat (default)                 ... PASS
  Test 0033:  Number of files using stat (aggr_cnv)                ... PASS
  Test 0034:  Number of blocks using stat (default)                ... PASS
  Test 0035:  Number of blocks using stat (aggr_cnv)               ... PASS
  Test 0040:  Files permissions (default)                          ... PASS
  Test 0041:  Files permissions (aggr_cnv)                         ... skip
  Test 0042:  Files permissions (set value)                        ... PASS
  Test 0043:  Files permissions (set value + aggr_cnv)             ... skip
  Test 0050:  Files owner (default)                                ... PASS
  Test 0051:  Files owner (aggr_cnv)                               ... skip
  Test 0052:  Files owner (set value)                              ... PASS
  Test 0053:  Files owner (set value + aggr_cnv)                   ... skip
  Test 0060:  Files size (default)                                 ... PASS
  Test 0061:  Files size (aggr_cnv)                                ... skip
  Test 0070:  Conventional file truncate                           ... skip
  Test 0071:  Conventional file truncate (aggr_cnv)                ... skip
  Test 0072:  Conventional file unlink                             ... skip
  Test 0073:  Conventional file unlink (aggr_cnv)                  ... skip
  Test 0074:  Conventional file random write                       ... skip
  Test 0075:  Conventional file random write (direct)              ... skip
  Test 0076:  Conventional file random write (aggr_cnv)            ... skip
  Test 0077:  Conventional file random write (aggr_cnv, direct)    ... skip
  Test 0078:  Conventional file mmap read/write                    ... skip
  Test 0079:  Conventional file mmap read/write (aggr_cnv)         ... skip
  Test 0080:  Sequential file truncate                             ... PASS
  Test 0081:  Sequential file unlink                               ... PASS
  Test 0082:  Sequential file buffered write IO                    ... PASS
  Test 0083:  Sequential file overwrite                            ... PASS
  Test 0084:  Sequential file unaligned write (sync IO)            ... PASS
  Test 0085:  Sequential file unaligned write (async IO)           ... PASS
  Test 0086:  Sequential file append (sync)                        ... PASS
  Test 0087:  Sequential file append (async)                       ... PASS
  Test 0088:  Sequential file random read                          ... PASS
  Test 0089:  Sequential file mmap read/write                      ... PASS
  Test 0090:  sequential file 4K synchronous write                 ... PASS
  Test 0091:  Sequential file large synchronous write              ... PASS

46 / 46 tests passed

* Without CONFIG_BLK_DEV_ZONED nvme tests :-
--------------------------------------------------------------------------------

#
# grep -i blk_dev_zoned .config
# CONFIG_BLK_DEV_ZONED is not set
# makej M=drivers/nvme/ clean 
  CLEAN   drivers/nvme//Module.symvers
# makej M=drivers/nvme/ 
  CC [M]  drivers/nvme//host/core.o
  CC [M]  drivers/nvme//host/trace.o
  CC [M]  drivers/nvme//host/lightnvm.o
  CC [M]  drivers/nvme//target/core.o
  CC [M]  drivers/nvme//host/hwmon.o
  CC [M]  drivers/nvme//target/configfs.o
  CC [M]  drivers/nvme//host/pci.o
  CC [M]  drivers/nvme//target/admin-cmd.o
  CC [M]  drivers/nvme//host/fabrics.o
  CC [M]  drivers/nvme//host/rdma.o
  CC [M]  drivers/nvme//target/fabrics-cmd.o
  CC [M]  drivers/nvme//target/discovery.o
  CC [M]  drivers/nvme//host/fc.o
  CC [M]  drivers/nvme//target/io-cmd-file.o
  CC [M]  drivers/nvme//host/tcp.o
  CC [M]  drivers/nvme//target/io-cmd-bdev.o
  CC [M]  drivers/nvme//target/passthru.o
  CC [M]  drivers/nvme//target/trace.o
  CC [M]  drivers/nvme//target/loop.o
  CC [M]  drivers/nvme//target/rdma.o
  CC [M]  drivers/nvme//target/fc.o
  CC [M]  drivers/nvme//target/fcloop.o
  CC [M]  drivers/nvme//target/tcp.o
  LD [M]  drivers/nvme//target/nvme-loop.o
  LD [M]  drivers/nvme//target/nvme-fcloop.o
  LD [M]  drivers/nvme//target/nvmet-tcp.o
  LD [M]  drivers/nvme//host/nvme-fabrics.o
  LD [M]  drivers/nvme//host/nvme.o
  LD [M]  drivers/nvme//host/nvme-rdma.o
  LD [M]  drivers/nvme//target/nvmet-rdma.o
  LD [M]  drivers/nvme//target/nvmet.o
  LD [M]  drivers/nvme//target/nvmet-fc.o
  LD [M]  drivers/nvme//host/nvme-tcp.o
  LD [M]  drivers/nvme//host/nvme-fc.o
  LD [M]  drivers/nvme//host/nvme-core.o
  MODPOST drivers/nvme//Module.symvers
  CC [M]  drivers/nvme//host/nvme-core.mod.o
  CC [M]  drivers/nvme//host/nvme-fabrics.mod.o
  CC [M]  drivers/nvme//host/nvme-fc.mod.o
  CC [M]  drivers/nvme//host/nvme-rdma.mod.o
  CC [M]  drivers/nvme//host/nvme-tcp.mod.o
  CC [M]  drivers/nvme//host/nvme.mod.o
  CC [M]  drivers/nvme//target/nvme-fcloop.mod.o
  CC [M]  drivers/nvme//target/nvme-loop.mod.o
  CC [M]  drivers/nvme//target/nvmet-fc.mod.o
  CC [M]  drivers/nvme//target/nvmet-rdma.mod.o
  CC [M]  drivers/nvme//target/nvmet-tcp.mod.o
  CC [M]  drivers/nvme//target/nvmet.mod.o
  LD [M]  drivers/nvme//target/nvme-fcloop.ko
  LD [M]  drivers/nvme//host/nvme-tcp.ko
  LD [M]  drivers/nvme//host/nvme-core.ko
  LD [M]  drivers/nvme//target/nvmet-tcp.ko
  LD [M]  drivers/nvme//target/nvme-loop.ko
  LD [M]  drivers/nvme//target/nvmet-fc.ko
  LD [M]  drivers/nvme//host/nvme-fabrics.ko
  LD [M]  drivers/nvme//host/nvme-fc.ko
  LD [M]  drivers/nvme//target/nvmet-rdma.ko
  LD [M]  drivers/nvme//host/nvme-rdma.ko
  LD [M]  drivers/nvme//host/nvme.ko
  LD [M]  drivers/nvme//target/nvmet.ko
#
# cdblktests 
# ./check tests/nvme/
nvme/002 (create many subsystems and test discovery)         [passed]
    runtime    ...  27.640s
nvme/003 (test if we're sending keep-alives to a discovery controller) [passed]
    runtime  10.145s  ...  10.147s
nvme/004 (test nvme and nvmet UUID NS descriptors)           [passed]
    runtime  1.713s  ...  1.712s
nvme/005 (reset local loopback target)                       [not run]
    nvme_core module does not have parameter multipath
nvme/006 (create an NVMeOF target with a block device-backed ns) [passed]
    runtime  0.111s  ...  0.115s
nvme/007 (create an NVMeOF target with a file-backed ns)     [passed]
    runtime  0.081s  ...  0.069s
nvme/008 (create an NVMeOF host with a block device-backed ns) [passed]
    runtime  1.690s  ...  1.727s
nvme/009 (create an NVMeOF host with a file-backed ns)       [passed]
    runtime  1.659s  ...  1.661s
nvme/010 (run data verification fio job on NVMeOF block device-backed ns) [passed]
    runtime  28.781s  ...  30.166s
nvme/011 (run data verification fio job on NVMeOF file-backed ns) [passed]
    runtime  253.831s  ...  238.774s
nvme/012 (run mkfs and data verification fio job on NVMeOF block device-backed ns) [passed]
    runtime  40.003s  ...  68.076s
nvme/013 (run mkfs and data verification fio job on NVMeOF file-backed ns) [passed]
    runtime  272.649s  ...  283.720s
nvme/014 (flush a NVMeOF block device-backed ns)             [passed]
    runtime  21.772s  ...  21.397s
nvme/015 (unit test for NVMe flush for file backed ns)       [passed]
    runtime  21.908s  ...  18.622s
nvme/016 (create/delete many NVMeOF block device-backed ns and test discovery) [passed]
    runtime  15.860s  ...  18.313s
nvme/017 (create/delete many file-ns and test discovery)     [passed]
    runtime  16.470s  ...  18.374s
nvme/018 (unit test NVMe-oF out of range access on a file backend) [passed]
    runtime  1.665s  ...  1.890s
nvme/019 (test NVMe DSM Discard command on NVMeOF block-device ns) [passed]
    runtime  1.681s  ...  1.982s
nvme/020 (test NVMe DSM Discard command on NVMeOF file-backed ns) [passed]
    runtime  1.645s  ...  1.913s
nvme/021 (test NVMe list command on NVMeOF file-backed ns)   [passed]
    runtime  1.648s  ...  1.956s
nvme/022 (test NVMe reset command on NVMeOF file-backed ns)  [passed]
    runtime  2.063s  ...  2.553s
nvme/023 (test NVMe smart-log command on NVMeOF block-device ns) [passed]
    runtime  1.692s  ...  2.588s
nvme/024 (test NVMe smart-log command on NVMeOF file-backed ns) [passed]
    runtime  1.643s  ...  1.656s
nvme/025 (test NVMe effects-log command on NVMeOF file-backed ns) [passed]
    runtime  1.640s  ...  1.668s
nvme/026 (test NVMe ns-descs command on NVMeOF file-backed ns) [passed]
    runtime  1.643s  ...  1.961s
nvme/027 (test NVMe ns-rescan command on NVMeOF file-backed ns) [passed]
    runtime  1.641s  ...  1.677s
nvme/028 (test NVMe list-subsys command on NVMeOF file-backed ns) [passed]
    runtime  1.648s  ...  1.868s
nvme/029 (test userspace IO via nvme-cli read/write interface) [passed]
    runtime  1.982s  ...  2.703s
nvme/030 (ensure the discovery generation counter is updated appropriately) [passed]
    runtime  0.308s  ...  0.328s
nvme/031 (test deletion of NVMeOF controllers immediately after setup) [passed]
    runtime  5.432s  ...  7.495s
nvme/038 (test deletion of NVMeOF subsystem without enabling) [passed]
    runtime  0.053s  ...  0.046s

* With CONFIG_BLK_DEV_ZONED nvme and zonefs tests on membacked null_blk zoned :-
--------------------------------------------------------------------------------

# grep -i blk_dev_zoned .config
CONFIG_BLK_DEV_ZONED=y
# make M=drivers/nvme/ clean 
  CLEAN   drivers/nvme//Module.symvers
# make M=drivers/nvme/ 
  CC [M]  drivers/nvme//host/core.o
  CC [M]  drivers/nvme//host/trace.o
  CC [M]  drivers/nvme//host/lightnvm.o
  CC [M]  drivers/nvme//host/zns.o
  CC [M]  drivers/nvme//host/hwmon.o
  LD [M]  drivers/nvme//host/nvme-core.o
  CC [M]  drivers/nvme//host/pci.o
  LD [M]  drivers/nvme//host/nvme.o
  CC [M]  drivers/nvme//host/fabrics.o
  LD [M]  drivers/nvme//host/nvme-fabrics.o
  CC [M]  drivers/nvme//host/rdma.o
  LD [M]  drivers/nvme//host/nvme-rdma.o
  CC [M]  drivers/nvme//host/fc.o
  LD [M]  drivers/nvme//host/nvme-fc.o
  CC [M]  drivers/nvme//host/tcp.o
  LD [M]  drivers/nvme//host/nvme-tcp.o
  CC [M]  drivers/nvme//target/core.o
  CC [M]  drivers/nvme//target/configfs.o
  CC [M]  drivers/nvme//target/admin-cmd.o
  CC [M]  drivers/nvme//target/fabrics-cmd.o
  CC [M]  drivers/nvme//target/discovery.o
  CC [M]  drivers/nvme//target/io-cmd-file.o
  CC [M]  drivers/nvme//target/io-cmd-bdev.o
  CC [M]  drivers/nvme//target/passthru.o
  CC [M]  drivers/nvme//target/zns.o
  CC [M]  drivers/nvme//target/trace.o
  LD [M]  drivers/nvme//target/nvmet.o
  CC [M]  drivers/nvme//target/loop.o
  LD [M]  drivers/nvme//target/nvme-loop.o
  CC [M]  drivers/nvme//target/rdma.o
  LD [M]  drivers/nvme//target/nvmet-rdma.o
  CC [M]  drivers/nvme//target/fc.o
  LD [M]  drivers/nvme//target/nvmet-fc.o
  CC [M]  drivers/nvme//target/fcloop.o
  LD [M]  drivers/nvme//target/nvme-fcloop.o
  CC [M]  drivers/nvme//target/tcp.o
  LD [M]  drivers/nvme//target/nvmet-tcp.o
  MODPOST drivers/nvme//Module.symvers
  CC [M]  drivers/nvme//host/nvme-core.mod.o
  LD [M]  drivers/nvme//host/nvme-core.ko
  CC [M]  drivers/nvme//host/nvme-fabrics.mod.o
  LD [M]  drivers/nvme//host/nvme-fabrics.ko
  CC [M]  drivers/nvme//host/nvme-fc.mod.o
  LD [M]  drivers/nvme//host/nvme-fc.ko
  CC [M]  drivers/nvme//host/nvme-rdma.mod.o
  LD [M]  drivers/nvme//host/nvme-rdma.ko
  CC [M]  drivers/nvme//host/nvme-tcp.mod.o
  LD [M]  drivers/nvme//host/nvme-tcp.ko
  CC [M]  drivers/nvme//host/nvme.mod.o
  LD [M]  drivers/nvme//host/nvme.ko
  CC [M]  drivers/nvme//target/nvme-fcloop.mod.o
  LD [M]  drivers/nvme//target/nvme-fcloop.ko
  CC [M]  drivers/nvme//target/nvme-loop.mod.o
  LD [M]  drivers/nvme//target/nvme-loop.ko
  CC [M]  drivers/nvme//target/nvmet-fc.mod.o
  LD [M]  drivers/nvme//target/nvmet-fc.ko
  CC [M]  drivers/nvme//target/nvmet-rdma.mod.o
  LD [M]  drivers/nvme//target/nvmet-rdma.ko
  CC [M]  drivers/nvme//target/nvmet-tcp.mod.o
  LD [M]  drivers/nvme//target/nvmet-tcp.ko
  CC [M]  drivers/nvme//target/nvmet.mod.o
  LD [M]  drivers/nvme//target/nvmet.ko
# 
# cdblktests 
# ./check tests/nvme/
nvme/002 (create many subsystems and test discovery)         [passed]
    runtime  24.378s  ...  24.636s
nvme/003 (test if we're sending keep-alives to a discovery controller) [passed]
    runtime  10.133s  ...  10.152s
nvme/004 (test nvme and nvmet UUID NS descriptors)           [passed]
    runtime  2.463s  ...  2.478s
nvme/005 (reset local loopback target)                       [not run]
    nvme_core module does not have parameter multipath
nvme/006 (create an NVMeOF target with a block device-backed ns) [passed]
    runtime  0.095s  ...  0.122s
nvme/007 (create an NVMeOF target with a file-backed ns)     [passed]
    runtime  0.065s  ...  0.079s
nvme/008 (create an NVMeOF host with a block device-backed ns) [passed]
    runtime  2.473s  ...  2.501s
nvme/009 (create an NVMeOF host with a file-backed ns)       [passed]
    runtime  2.460s  ...  2.424s
nvme/010 (run data verification fio job on NVMeOF block device-backed ns) [passed]
    runtime  24.526s  ...  28.015s
nvme/011 (run data verification fio job on NVMeOF file-backed ns) [passed]
    runtime  265.967s  ...  282.717s
nvme/012 (run mkfs and data verification fio job on NVMeOF block device-backed ns) [passed]
    runtime  44.665s  ...  48.124s
nvme/013 (run mkfs and data verification fio job on NVMeOF file-backed ns) [passed]
    runtime  261.739s  ...  352.331s
nvme/014 (flush a NVMeOF block device-backed ns)             [passed]
    runtime  21.268s  ...  22.013s
nvme/015 (unit test for NVMe flush for file backed ns)       [passed]
    runtime  18.820s  ...  22.104s
nvme/016 (create/delete many NVMeOF block device-backed ns and test discovery) [passed]
    runtime  13.899s  ...  14.322s
nvme/017 (create/delete many file-ns and test discovery)     [passed]
    runtime  14.322s  ...  14.031s
nvme/018 (unit test NVMe-oF out of range access on a file backend) [passed]
    runtime  2.450s  ...  2.444s
nvme/019 (test NVMe DSM Discard command on NVMeOF block-device ns) [passed]
    runtime  2.475s  ...  2.489s
nvme/020 (test NVMe DSM Discard command on NVMeOF file-backed ns) [passed]
    runtime  2.410s  ...  2.448s
nvme/021 (test NVMe list command on NVMeOF file-backed ns)   [passed]
    runtime  2.441s  ...  2.439s
nvme/022 (test NVMe reset command on NVMeOF file-backed ns)  [passed]
    runtime  2.864s  ...  2.863s
nvme/023 (test NVMe smart-log command on NVMeOF block-device ns) [passed]
    runtime  2.465s  ...  2.446s
nvme/024 (test NVMe smart-log command on NVMeOF file-backed ns) [passed]
    runtime  2.416s  ...  2.411s
nvme/025 (test NVMe effects-log command on NVMeOF file-backed ns) [passed]
    runtime  2.419s  ...  2.748s
nvme/026 (test NVMe ns-descs command on NVMeOF file-backed ns) [passed]
    runtime  2.422s  ...  2.410s
nvme/027 (test NVMe ns-rescan command on NVMeOF file-backed ns) [passed]
    runtime  2.456s  ...  2.462s
nvme/028 (test NVMe list-subsys command on NVMeOF file-backed ns) [passed]
    runtime  2.427s  ...  2.429s
nvme/029 (test userspace IO via nvme-cli read/write interface) [passed]
    runtime  2.751s  ...  2.755s
nvme/030 (ensure the discovery generation counter is updated appropriately) [passed]
    runtime  0.346s  ...  0.357s
nvme/031 (test deletion of NVMeOF controllers immediately after setup) [passed]
    runtime  13.601s  ...  13.591s
nvme/038 (test deletion of NVMeOF subsystem without enabling) [passed]
    runtime  0.039s  ...  0.059s
#
# cdzonefstest 
# ./zonefs-tests.sh /dev/nvme1n1 
Gathering information on /dev/nvme1n1...
zonefs-tests on /dev/nvme1n1:
  16 zones (0 conventional zones, 16 sequential zones)
  131072 512B sectors zone size (64 MiB)
  1 max open zones
Running tests
  Test 0010:  mkzonefs (options)                                   ... PASS
  Test 0011:  mkzonefs (force format)                              ... PASS
  Test 0012:  mkzonefs (invalid device)                            ... PASS
  Test 0013:  mkzonefs (super block zone state)                    ... PASS
  Test 0020:  mount (default)                                      ... PASS
  Test 0021:  mount (invalid device)                               ... PASS
  Test 0022:  mount (check mount directory sub-directories)        ... PASS
  Test 0023:  mount (options)                                      ... PASS
  Test 0030:  Number of files (default)                            ... PASS
  Test 0031:  Number of files (aggr_cnv)                           ... skip
  Test 0032:  Number of files using stat (default)                 ... PASS
  Test 0033:  Number of files using stat (aggr_cnv)                ... PASS
  Test 0034:  Number of blocks using stat (default)                ... PASS
  Test 0035:  Number of blocks using stat (aggr_cnv)               ... PASS
  Test 0040:  Files permissions (default)                          ... PASS
  Test 0041:  Files permissions (aggr_cnv)                         ... skip
  Test 0042:  Files permissions (set value)                        ... PASS
  Test 0043:  Files permissions (set value + aggr_cnv)             ... skip
  Test 0050:  Files owner (default)                                ... PASS
  Test 0051:  Files owner (aggr_cnv)                               ... skip
  Test 0052:  Files owner (set value)                              ... PASS
  Test 0053:  Files owner (set value + aggr_cnv)                   ... skip
  Test 0060:  Files size (default)                                 ... PASS
  Test 0061:  Files size (aggr_cnv)                                ... skip
  Test 0070:  Conventional file truncate                           ... skip
  Test 0071:  Conventional file truncate (aggr_cnv)                ... skip
  Test 0072:  Conventional file unlink                             ... skip
  Test 0073:  Conventional file unlink (aggr_cnv)                  ... skip
  Test 0074:  Conventional file random write                       ... skip
  Test 0075:  Conventional file random write (direct)              ... skip
  Test 0076:  Conventional file random write (aggr_cnv)            ... skip
  Test 0077:  Conventional file random write (aggr_cnv, direct)    ... skip
  Test 0078:  Conventional file mmap read/write                    ... skip
  Test 0079:  Conventional file mmap read/write (aggr_cnv)         ... skip
  Test 0080:  Sequential file truncate                             ... PASS
  Test 0081:  Sequential file unlink                               ... PASS
  Test 0082:  Sequential file buffered write IO                    ... PASS
  Test 0083:  Sequential file overwrite                            ... PASS
  Test 0084:  Sequential file unaligned write (sync IO)            ... PASS
  Test 0085:  Sequential file unaligned write (async IO)           ... PASS
  Test 0086:  Sequential file append (sync)                        ... PASS
  Test 0087:  Sequential file append (async)                       ... PASS
  Test 0088:  Sequential file random read                          ... PASS
  Test 0089:  Sequential file mmap read/write                      ... PASS
  Test 0090:  sequential file 4K synchronous write                 ... PASS
  Test 0091:  Sequential file large synchronous write              ... PASS

46 / 46 tests passed
-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Mon Jan 11 23:26:15 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Mon, 11 Jan 2021 20:26:15 -0800
Subject: [PATCH V9 1/9] block: export bio_add_hw_pages()
In-Reply-To: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210112042623.6316-2-chaitanya.kulkarni@wdc.com>

To implement the NVMe Zone Append command on the NVMeOF target side for
generic Zoned Block Devices with NVMe Zoned Namespaces interface, we
need to build the bios with hardware limitations, i.e. we use
bio_add_hw_page() with queue_max_zone_append_sectors() instead of
bio_add_page().

Without this API being exported NVMeOF target will require to use
bio_add_hw_page() caller bio_iov_iter_get_pages(). That results in
extra work which is inefficient.

Export the API so that NVMeOF ZBD over ZNS backend can use it to build
Zone Append bios.

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 block/bio.c            | 1 +
 block/blk.h            | 4 ----
 include/linux/blkdev.h | 4 ++++
 3 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/block/bio.c b/block/bio.c
index 1f2cc1fbe283..5cbd56b54f98 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -826,6 +826,7 @@ int bio_add_hw_page(struct request_queue *q, struct bio *bio,
 	bio->bi_iter.bi_size += len;
 	return len;
 }
+EXPORT_SYMBOL(bio_add_hw_page);
 
 /**
  * bio_add_pc_page	- attempt to add page to passthrough bio
diff --git a/block/blk.h b/block/blk.h
index 7550364c326c..200030b2d74f 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -351,8 +351,4 @@ int bdev_resize_partition(struct block_device *bdev, int partno,
 		sector_t start, sector_t length);
 int disk_expand_part_tbl(struct gendisk *disk, int target);
 
-int bio_add_hw_page(struct request_queue *q, struct bio *bio,
-		struct page *page, unsigned int len, unsigned int offset,
-		unsigned int max_sectors, bool *same_page);
-
 #endif /* BLK_INTERNAL_H */
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 070de09425ad..028ccc9bdf8d 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -2005,6 +2005,10 @@ struct block_device *I_BDEV(struct inode *inode);
 struct block_device *bdgrab(struct block_device *bdev);
 void bdput(struct block_device *);
 
+int bio_add_hw_page(struct request_queue *q, struct bio *bio,
+		struct page *page, unsigned int len, unsigned int offset,
+		unsigned int max_sectors, bool *same_page);
+
 #ifdef CONFIG_BLOCK
 void invalidate_bdev(struct block_device *bdev);
 int truncate_bdev_range(struct block_device *bdev, fmode_t mode, loff_t lstart,
-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Mon Jan 11 23:26:16 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Mon, 11 Jan 2021 20:26:16 -0800
Subject: [PATCH V9 2/9] nvmet: add lba to sect conversion helpers
In-Reply-To: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210112042623.6316-3-chaitanya.kulkarni@wdc.com>

In this preparation patch, we add helpers to convert lbas to sectors &
sectors to lba. This is needed to eliminate code duplication in the ZBD
backend.

Use these helpers in the block device backend.

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/target/io-cmd-bdev.c |  8 +++-----
 drivers/nvme/target/nvmet.h       | 10 ++++++++++
 2 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
index 125dde3f410e..23095bdfce06 100644
--- a/drivers/nvme/target/io-cmd-bdev.c
+++ b/drivers/nvme/target/io-cmd-bdev.c
@@ -256,8 +256,7 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req)
 	if (is_pci_p2pdma_page(sg_page(req->sg)))
 		op |= REQ_NOMERGE;
 
-	sector = le64_to_cpu(req->cmd->rw.slba);
-	sector <<= (req->ns->blksize_shift - 9);
+	sector = nvmet_lba_to_sect(req->ns, req->cmd->rw.slba);
 
 	if (req->transfer_len <= NVMET_MAX_INLINE_DATA_LEN) {
 		bio = &req->b.inline_bio;
@@ -345,7 +344,7 @@ static u16 nvmet_bdev_discard_range(struct nvmet_req *req,
 	int ret;
 
 	ret = __blkdev_issue_discard(ns->bdev,
-			le64_to_cpu(range->slba) << (ns->blksize_shift - 9),
+			nvmet_lba_to_sect(ns, range->slba),
 			le32_to_cpu(range->nlb) << (ns->blksize_shift - 9),
 			GFP_KERNEL, 0, bio);
 	if (ret && ret != -EOPNOTSUPP) {
@@ -414,8 +413,7 @@ static void nvmet_bdev_execute_write_zeroes(struct nvmet_req *req)
 	if (!nvmet_check_transfer_len(req, 0))
 		return;
 
-	sector = le64_to_cpu(write_zeroes->slba) <<
-		(req->ns->blksize_shift - 9);
+	sector = nvmet_lba_to_sect(req->ns, write_zeroes->slba);
 	nr_sector = (((sector_t)le16_to_cpu(write_zeroes->length) + 1) <<
 		(req->ns->blksize_shift - 9));
 
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 592763732065..8776dd1a0490 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -603,4 +603,14 @@ static inline bool nvmet_ns_has_pi(struct nvmet_ns *ns)
 	return ns->pi_type && ns->metadata_size == sizeof(struct t10_pi_tuple);
 }
 
+static inline __le64 nvmet_sect_to_lba(struct nvmet_ns *ns, sector_t sect)
+{
+	return cpu_to_le64(sect >> (ns->blksize_shift - SECTOR_SHIFT));
+}
+
+static inline sector_t nvmet_lba_to_sect(struct nvmet_ns *ns, __le64 lba)
+{
+	return le64_to_cpu(lba) << (ns->blksize_shift - SECTOR_SHIFT);
+}
+
 #endif /* _NVMET_H */
-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Mon Jan 11 23:26:17 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Mon, 11 Jan 2021 20:26:17 -0800
Subject: [PATCH V9 3/9] nvmet: add NVM command set identifier support
In-Reply-To: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210112042623.6316-4-chaitanya.kulkarni@wdc.com>

NVMe TP 4056 allows controller to support different command sets.
NVMeoF target currently only supports namespaces that contain
traditional logical blocks that may be randomly read and written. In
some applications there is value in exposing namespaces that contain
logical blocks that have special access rules (e.g. sequentially write
required namespace such as Zoned Namespace (ZNS)).

In order to support the Zoned Block Devices (ZBD) backend, controller
needs to have support for ZNS Command Set Identifier (CSI).

In this preparation patch, we adjust the code such that it can now
support different command sets. We update the namespace data
structure to store the CSI value which defaults to NVME_CSI_NVM
which represents traditional logical blocks namespace type.

The CSI support is required to implement the ZBD backend over NVMe ZNS
interface, since ZNS commands belongs to the different command set than
the default one.

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/target/admin-cmd.c | 39 ++++++++++++++++++++++-----------
 drivers/nvme/target/core.c      | 13 ++++++++++-
 drivers/nvme/target/nvmet.h     |  1 +
 3 files changed, 39 insertions(+), 14 deletions(-)

diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index 220edacfccfb..a50b7bcac67a 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -175,19 +175,26 @@ static void nvmet_execute_get_log_cmd_effects_ns(struct nvmet_req *req)
 	if (!log)
 		goto out;
 
-	log->acs[nvme_admin_get_log_page]	= cpu_to_le32(1 << 0);
-	log->acs[nvme_admin_identify]		= cpu_to_le32(1 << 0);
-	log->acs[nvme_admin_abort_cmd]		= cpu_to_le32(1 << 0);
-	log->acs[nvme_admin_set_features]	= cpu_to_le32(1 << 0);
-	log->acs[nvme_admin_get_features]	= cpu_to_le32(1 << 0);
-	log->acs[nvme_admin_async_event]	= cpu_to_le32(1 << 0);
-	log->acs[nvme_admin_keep_alive]		= cpu_to_le32(1 << 0);
-
-	log->iocs[nvme_cmd_read]		= cpu_to_le32(1 << 0);
-	log->iocs[nvme_cmd_write]		= cpu_to_le32(1 << 0);
-	log->iocs[nvme_cmd_flush]		= cpu_to_le32(1 << 0);
-	log->iocs[nvme_cmd_dsm]			= cpu_to_le32(1 << 0);
-	log->iocs[nvme_cmd_write_zeroes]	= cpu_to_le32(1 << 0);
+	switch (req->cmd->get_log_page.csi) {
+	case NVME_CSI_NVM:
+		log->acs[nvme_admin_get_log_page]	= cpu_to_le32(1 << 0);
+		log->acs[nvme_admin_identify]		= cpu_to_le32(1 << 0);
+		log->acs[nvme_admin_abort_cmd]		= cpu_to_le32(1 << 0);
+		log->acs[nvme_admin_set_features]	= cpu_to_le32(1 << 0);
+		log->acs[nvme_admin_get_features]	= cpu_to_le32(1 << 0);
+		log->acs[nvme_admin_async_event]	= cpu_to_le32(1 << 0);
+		log->acs[nvme_admin_keep_alive]		= cpu_to_le32(1 << 0);
+
+		log->iocs[nvme_cmd_read]		= cpu_to_le32(1 << 0);
+		log->iocs[nvme_cmd_write]		= cpu_to_le32(1 << 0);
+		log->iocs[nvme_cmd_flush]		= cpu_to_le32(1 << 0);
+		log->iocs[nvme_cmd_dsm]			= cpu_to_le32(1 << 0);
+		log->iocs[nvme_cmd_write_zeroes]	= cpu_to_le32(1 << 0);
+		break;
+	default:
+		status = NVME_SC_INVALID_LOG_PAGE;
+		break;
+	}
 
 	status = nvmet_copy_to_sgl(req, 0, log, sizeof(*log));
 
@@ -606,6 +613,7 @@ static u16 nvmet_copy_ns_identifier(struct nvmet_req *req, u8 type, u8 len,
 
 static void nvmet_execute_identify_desclist(struct nvmet_req *req)
 {
+	u16 nvme_cis_nvm = NVME_CSI_NVM;
 	u16 status = 0;
 	off_t off = 0;
 
@@ -631,6 +639,11 @@ static void nvmet_execute_identify_desclist(struct nvmet_req *req)
 			goto out;
 	}
 
+	status = nvmet_copy_ns_identifier(req, NVME_NIDT_CSI, NVME_NIDT_CSI_LEN,
+					  &nvme_cis_nvm, &off);
+	if (status)
+		goto out;
+
 	if (sg_zero_buffer(req->sg, req->sg_cnt, NVME_IDENTIFY_DATA_SIZE - off,
 			off) != NVME_IDENTIFY_DATA_SIZE - off)
 		status = NVME_SC_INTERNAL | NVME_SC_DNR;
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index 8ce4d59cc9e7..672e4009f8d6 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -681,6 +681,7 @@ struct nvmet_ns *nvmet_ns_alloc(struct nvmet_subsys *subsys, u32 nsid)
 
 	uuid_gen(&ns->uuid);
 	ns->buffered_io = false;
+	ns->csi = NVME_CSI_NVM;
 
 	return ns;
 }
@@ -1103,6 +1104,16 @@ static inline u8 nvmet_cc_iocqes(u32 cc)
 	return (cc >> NVME_CC_IOCQES_SHIFT) & 0xf;
 }
 
+static inline bool nvmet_cc_css_check(u8 cc_css)
+{
+	switch (cc_css <<= NVME_CC_CSS_SHIFT) {
+	case NVME_CC_CSS_NVM:
+		return true;
+	default:
+		return false;
+	}
+}
+
 static void nvmet_start_ctrl(struct nvmet_ctrl *ctrl)
 {
 	lockdep_assert_held(&ctrl->lock);
@@ -1111,7 +1122,7 @@ static void nvmet_start_ctrl(struct nvmet_ctrl *ctrl)
 	    nvmet_cc_iocqes(ctrl->cc) != NVME_NVM_IOCQES ||
 	    nvmet_cc_mps(ctrl->cc) != 0 ||
 	    nvmet_cc_ams(ctrl->cc) != 0 ||
-	    nvmet_cc_css(ctrl->cc) != 0) {
+	    !nvmet_cc_css_check(nvmet_cc_css(ctrl->cc))) {
 		ctrl->csts = NVME_CSTS_CFS;
 		return;
 	}
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 8776dd1a0490..476b3cd91c65 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -81,6 +81,7 @@ struct nvmet_ns {
 	struct pci_dev		*p2p_dev;
 	int			pi_type;
 	int			metadata_size;
+	u8			csi;
 };
 
 static inline struct nvmet_ns *to_nvmet_ns(struct config_item *item)
-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Mon Jan 11 23:26:18 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Mon, 11 Jan 2021 20:26:18 -0800
Subject: [PATCH V9 4/9] nvmet: add ZBD over ZNS backend support
In-Reply-To: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210112042623.6316-5-chaitanya.kulkarni@wdc.com>

NVMe TP 4053 ? Zoned Namespaces (ZNS) allows host software to
communicate with a non-volatile memory subsystem using zones for
NVMe protocol based controllers. NVMeOF already support the ZNS NVMe
Protocol compliant devices on the target in the passthru mode. There
are Generic zoned block devices like  Shingled Magnetic Recording (SMR)
HDDs that are not based on the NVMe protocol.

This patch adds ZNS backend to support the ZBDs for NVMeOF target.

This support includes implementing the new command set NVME_CSI_ZNS,
adding different command handlers for ZNS command set such as
NVMe Identify Controller, NVMe Identify Namespace, NVMe Zone Append,
NVMe Zone Management Send and NVMe Zone Management Receive.

With new command set identifier we also update the target command effects
logs to reflect the ZNS compliant commands.

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/target/Makefile      |   1 +
 drivers/nvme/target/admin-cmd.c   |  28 +++
 drivers/nvme/target/core.c        |   3 +
 drivers/nvme/target/io-cmd-bdev.c |  33 ++-
 drivers/nvme/target/nvmet.h       |  38 ++++
 drivers/nvme/target/zns.c         | 342 ++++++++++++++++++++++++++++++
 6 files changed, 437 insertions(+), 8 deletions(-)
 create mode 100644 drivers/nvme/target/zns.c

diff --git a/drivers/nvme/target/Makefile b/drivers/nvme/target/Makefile
index ebf91fc4c72e..9837e580fa7e 100644
--- a/drivers/nvme/target/Makefile
+++ b/drivers/nvme/target/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_NVME_TARGET_TCP)		+= nvmet-tcp.o
 nvmet-y		+= core.o configfs.o admin-cmd.o fabrics-cmd.o \
 			discovery.o io-cmd-file.o io-cmd-bdev.o
 nvmet-$(CONFIG_NVME_TARGET_PASSTHRU)	+= passthru.o
+nvmet-$(CONFIG_BLK_DEV_ZONED)		+= zns.o
 nvme-loop-y	+= loop.o
 nvmet-rdma-y	+= rdma.o
 nvmet-fc-y	+= fc.o
diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index a50b7bcac67a..bdf09d8faa48 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -191,6 +191,15 @@ static void nvmet_execute_get_log_cmd_effects_ns(struct nvmet_req *req)
 		log->iocs[nvme_cmd_dsm]			= cpu_to_le32(1 << 0);
 		log->iocs[nvme_cmd_write_zeroes]	= cpu_to_le32(1 << 0);
 		break;
+	case NVME_CSI_ZNS:
+		if (IS_ENABLED(CONFIG_BLK_DEV_ZONED)) {
+			u32 *iocs = log->iocs;
+
+			iocs[nvme_cmd_zone_append]	= cpu_to_le32(1 << 0);
+			iocs[nvme_cmd_zone_mgmt_send]	= cpu_to_le32(1 << 0);
+			iocs[nvme_cmd_zone_mgmt_recv]	= cpu_to_le32(1 << 0);
+		}
+		break;
 	default:
 		status = NVME_SC_INVALID_LOG_PAGE;
 		break;
@@ -644,6 +653,17 @@ static void nvmet_execute_identify_desclist(struct nvmet_req *req)
 	if (status)
 		goto out;
 
+	if (IS_ENABLED(CONFIG_BLK_DEV_ZONED)) {
+		u16 nvme_cis_zns = NVME_CSI_ZNS;
+
+		if (req->ns->csi == NVME_CSI_ZNS)
+			status = nvmet_copy_ns_identifier(req, NVME_NIDT_CSI,
+							  NVME_NIDT_CSI_LEN,
+							  &nvme_cis_zns, &off);
+		if (status)
+			goto out;
+	}
+
 	if (sg_zero_buffer(req->sg, req->sg_cnt, NVME_IDENTIFY_DATA_SIZE - off,
 			off) != NVME_IDENTIFY_DATA_SIZE - off)
 		status = NVME_SC_INTERNAL | NVME_SC_DNR;
@@ -660,8 +680,16 @@ static void nvmet_execute_identify(struct nvmet_req *req)
 	switch (req->cmd->identify.cns) {
 	case NVME_ID_CNS_NS:
 		return nvmet_execute_identify_ns(req);
+	case NVME_ID_CNS_CS_NS:
+		if (req->cmd->identify.csi == NVME_CSI_ZNS)
+			return nvmet_execute_identify_cns_cs_ns(req);
+		break;
 	case NVME_ID_CNS_CTRL:
 		return nvmet_execute_identify_ctrl(req);
+	case NVME_ID_CNS_CS_CTRL:
+		if (req->cmd->identify.csi == NVME_CSI_ZNS)
+			return nvmet_execute_identify_cns_cs_ctrl(req);
+		break;
 	case NVME_ID_CNS_NS_ACTIVE_LIST:
 		return nvmet_execute_identify_nslist(req);
 	case NVME_ID_CNS_NS_DESC_LIST:
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index 672e4009f8d6..17d5da062a5a 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -1107,6 +1107,7 @@ static inline u8 nvmet_cc_iocqes(u32 cc)
 static inline bool nvmet_cc_css_check(u8 cc_css)
 {
 	switch (cc_css <<= NVME_CC_CSS_SHIFT) {
+	case NVME_CC_CSS_CSI:
 	case NVME_CC_CSS_NVM:
 		return true;
 	default:
@@ -1173,6 +1174,8 @@ static void nvmet_init_cap(struct nvmet_ctrl *ctrl)
 {
 	/* command sets supported: NVMe command set: */
 	ctrl->cap = (1ULL << 37);
+	if (IS_ENABLED(CONFIG_BLK_DEV_ZONED))
+		ctrl->cap |= (1ULL << 43);
 	/* CC.EN timeout in 500msec units: */
 	ctrl->cap |= (15ULL << 24);
 	/* maximum queue entries supported: */
diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
index 23095bdfce06..6178ef643962 100644
--- a/drivers/nvme/target/io-cmd-bdev.c
+++ b/drivers/nvme/target/io-cmd-bdev.c
@@ -63,6 +63,14 @@ static void nvmet_bdev_ns_enable_integrity(struct nvmet_ns *ns)
 	}
 }
 
+void nvmet_bdev_ns_disable(struct nvmet_ns *ns)
+{
+	if (ns->bdev) {
+		blkdev_put(ns->bdev, FMODE_WRITE | FMODE_READ);
+		ns->bdev = NULL;
+	}
+}
+
 int nvmet_bdev_ns_enable(struct nvmet_ns *ns)
 {
 	int ret;
@@ -86,15 +94,15 @@ int nvmet_bdev_ns_enable(struct nvmet_ns *ns)
 	if (IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY_T10))
 		nvmet_bdev_ns_enable_integrity(ns);
 
-	return 0;
-}
-
-void nvmet_bdev_ns_disable(struct nvmet_ns *ns)
-{
-	if (ns->bdev) {
-		blkdev_put(ns->bdev, FMODE_WRITE | FMODE_READ);
-		ns->bdev = NULL;
+	if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) && bdev_is_zoned(ns->bdev)) {
+		if (!nvmet_bdev_zns_enable(ns)) {
+			nvmet_bdev_ns_disable(ns);
+			return -EINVAL;
+		}
+		ns->csi = NVME_CSI_ZNS;
 	}
+
+	return 0;
 }
 
 void nvmet_bdev_ns_revalidate(struct nvmet_ns *ns)
@@ -448,6 +456,15 @@ u16 nvmet_bdev_parse_io_cmd(struct nvmet_req *req)
 	case nvme_cmd_write_zeroes:
 		req->execute = nvmet_bdev_execute_write_zeroes;
 		return 0;
+	case nvme_cmd_zone_append:
+		req->execute = nvmet_bdev_execute_zone_append;
+		return 0;
+	case nvme_cmd_zone_mgmt_recv:
+		req->execute = nvmet_bdev_execute_zone_mgmt_recv;
+		return 0;
+	case nvme_cmd_zone_mgmt_send:
+		req->execute = nvmet_bdev_execute_zone_mgmt_send;
+		return 0;
 	default:
 		pr_err("unhandled cmd %d on qid %d\n", cmd->common.opcode,
 		       req->sq->qid);
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 476b3cd91c65..7361665585a2 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -252,6 +252,10 @@ struct nvmet_subsys {
 	unsigned int		admin_timeout;
 	unsigned int		io_timeout;
 #endif /* CONFIG_NVME_TARGET_PASSTHRU */
+
+#ifdef CONFIG_BLK_DEV_ZONED
+	u8			zasl;
+#endif /* CONFIG_BLK_DEV_ZONED */
 };
 
 static inline struct nvmet_subsys *to_subsys(struct config_item *item)
@@ -614,4 +618,38 @@ static inline sector_t nvmet_lba_to_sect(struct nvmet_ns *ns, __le64 lba)
 	return le64_to_cpu(lba) << (ns->blksize_shift - SECTOR_SHIFT);
 }
 
+#ifdef CONFIG_BLK_DEV_ZONED
+bool nvmet_bdev_zns_enable(struct nvmet_ns *ns);
+void nvmet_execute_identify_cns_cs_ctrl(struct nvmet_req *req);
+void nvmet_execute_identify_cns_cs_ns(struct nvmet_req *req);
+void nvmet_bdev_execute_zone_mgmt_recv(struct nvmet_req *req);
+void nvmet_bdev_execute_zone_mgmt_send(struct nvmet_req *req);
+void nvmet_bdev_execute_zone_append(struct nvmet_req *req);
+#else  /* CONFIG_BLK_DEV_ZONED */
+static inline bool nvmet_bdev_zns_enable(struct nvmet_ns *ns)
+{
+	return false;
+}
+static inline void
+nvmet_execute_identify_cns_cs_ctrl(struct nvmet_req *req)
+{
+}
+static inline void
+nvmet_execute_identify_cns_cs_ns(struct nvmet_req *req)
+{
+}
+static inline void
+nvmet_bdev_execute_zone_mgmt_recv(struct nvmet_req *req)
+{
+}
+static inline void
+nvmet_bdev_execute_zone_mgmt_send(struct nvmet_req *req)
+{
+}
+static inline void
+nvmet_bdev_execute_zone_append(struct nvmet_req *req)
+{
+}
+#endif /* CONFIG_BLK_DEV_ZONED */
+
 #endif /* _NVMET_H */
diff --git a/drivers/nvme/target/zns.c b/drivers/nvme/target/zns.c
new file mode 100644
index 000000000000..2a71f56e568d
--- /dev/null
+++ b/drivers/nvme/target/zns.c
@@ -0,0 +1,342 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * NVMe ZNS-ZBD command implementation.
+ * Copyright (c) 2020-2021 HGST, a Western Digital Company.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/nvme.h>
+#include <linux/blkdev.h>
+#include "nvmet.h"
+
+/*
+ * We set the Memory Page Size Minimum (MPSMIN) for target controller to 0
+ * which gets added by 12 in the nvme_enable_ctrl() which results in 2^12 = 4k
+ * as page_shift value. When calculating the ZASL use shift by 12.
+ */
+#define NVMET_MPSMIN_SHIFT	12
+
+static u16 nvmet_bdev_zns_checks(struct nvmet_req *req)
+{
+	u16 status = NVME_SC_SUCCESS;
+
+	if (!bdev_is_zoned(req->ns->bdev)) {
+		status = NVME_SC_INVALID_NS | NVME_SC_DNR;
+		goto out;
+	}
+
+	if (req->cmd->zmr.zra != NVME_ZRA_ZONE_REPORT) {
+		status = NVME_SC_INVALID_FIELD;
+		goto out;
+	}
+
+	if (req->cmd->zmr.zrasf != NVME_ZRASF_ZONE_REPORT_ALL) {
+		status = NVME_SC_INVALID_FIELD;
+		goto out;
+	}
+
+	if (req->cmd->zmr.pr != NVME_REPORT_ZONE_PARTIAL)
+		status = NVME_SC_INVALID_FIELD;
+
+out:
+	return status;
+}
+
+/*
+ *  ZNS related command implementation and helpers.
+ */
+
+static inline u8 nvmet_zasl(unsigned int zone_append_sects)
+{
+	/*
+	 * Zone Append Size Limit is the value experessed in the units
+	 * of minimum memory page size (i.e. 12) and is reported power of 2.
+	 */
+	return ilog2((zone_append_sects << 9) >> NVMET_MPSMIN_SHIFT);
+}
+
+static inline bool nvmet_zns_update_zasl(struct nvmet_ns *ns)
+{
+	struct request_queue *q = ns->bdev->bd_disk->queue;
+	u8 zasl = nvmet_zasl(queue_max_zone_append_sectors(q));
+
+	if (ns->subsys->zasl)
+		return ns->subsys->zasl < zasl ? false : true;
+
+	ns->subsys->zasl = zasl;
+	return true;
+}
+
+
+static int nvmet_bdev_validate_zns_zones_cb(struct blk_zone *z,
+					    unsigned int idx, void *data)
+{
+	if (z->type == BLK_ZONE_TYPE_CONVENTIONAL)
+		return -EOPNOTSUPP;
+	return 0;
+}
+
+static bool nvmet_bdev_has_conv_zones(struct block_device *bdev)
+{
+	int ret;
+
+	if (bdev->bd_disk->queue->conv_zones_bitmap)
+		return true;
+
+	ret = blkdev_report_zones(bdev, 0, blkdev_nr_zones(bdev->bd_disk),
+				  nvmet_bdev_validate_zns_zones_cb, NULL);
+
+	return ret < 0 ? true : false;
+}
+
+bool nvmet_bdev_zns_enable(struct nvmet_ns *ns)
+{
+	if (nvmet_bdev_has_conv_zones(ns->bdev))
+		return false;
+
+	/*
+	 * For ZBC and ZAC devices, writes into sequential zones must be aligned
+	 * to the device physical block size. So use this value as the logical
+	 * block size to avoid errors.
+	 */
+	ns->blksize_shift = blksize_bits(bdev_physical_block_size(ns->bdev));
+
+	if (!nvmet_zns_update_zasl(ns))
+		return false;
+
+	return !(get_capacity(ns->bdev->bd_disk) &
+			(bdev_zone_sectors(ns->bdev) - 1));
+}
+
+/*
+ * ZNS related Admin and I/O command handlers.
+ */
+void nvmet_execute_identify_cns_cs_ctrl(struct nvmet_req *req)
+{
+	u8 zasl = req->sq->ctrl->subsys->zasl;
+	struct nvmet_ctrl *ctrl = req->sq->ctrl;
+	struct nvme_id_ctrl_zns *id;
+	u16 status;
+
+	id = kzalloc(sizeof(*id), GFP_KERNEL);
+	if (!id) {
+		status = NVME_SC_INTERNAL;
+		goto out;
+	}
+
+	if (ctrl->ops->get_mdts)
+		id->zasl = min_t(u8, ctrl->ops->get_mdts(ctrl), zasl);
+	else
+		id->zasl = zasl;
+
+	status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id));
+
+	kfree(id);
+out:
+	nvmet_req_complete(req, status);
+}
+
+void nvmet_execute_identify_cns_cs_ns(struct nvmet_req *req)
+{
+	struct nvme_id_ns_zns *id_zns;
+	u16 status = NVME_SC_SUCCESS;
+	u64 zsze;
+
+	if (le32_to_cpu(req->cmd->identify.nsid) == NVME_NSID_ALL) {
+		req->error_loc = offsetof(struct nvme_identify, nsid);
+		status = NVME_SC_INVALID_NS | NVME_SC_DNR;
+		goto out;
+	}
+
+	id_zns = kzalloc(sizeof(*id_zns), GFP_KERNEL);
+	if (!id_zns) {
+		status = NVME_SC_INTERNAL;
+		goto out;
+	}
+
+	req->ns = nvmet_find_namespace(req->sq->ctrl, req->cmd->identify.nsid);
+	if (!req->ns) {
+		status = NVME_SC_INTERNAL;
+		goto done;
+	}
+
+	if (!bdev_is_zoned(req->ns->bdev)) {
+		req->error_loc = offsetof(struct nvme_identify, nsid);
+		status = NVME_SC_INVALID_NS | NVME_SC_DNR;
+		goto done;
+	}
+
+	nvmet_ns_revalidate(req->ns);
+	zsze = (bdev_zone_sectors(req->ns->bdev) << 9) >>
+					req->ns->blksize_shift;
+	id_zns->lbafe[0].zsze = cpu_to_le64(zsze);
+	id_zns->mor = cpu_to_le32(bdev_max_open_zones(req->ns->bdev));
+	id_zns->mar = cpu_to_le32(bdev_max_active_zones(req->ns->bdev));
+
+done:
+	status = nvmet_copy_to_sgl(req, 0, id_zns, sizeof(*id_zns));
+	kfree(id_zns);
+out:
+	nvmet_req_complete(req, status);
+}
+
+struct nvmet_report_zone_data {
+	struct nvmet_ns *ns;
+	struct nvme_zone_report *rz;
+};
+
+static int nvmet_bdev_report_zone_cb(struct blk_zone *z, unsigned int idx,
+				     void *data)
+{
+	struct nvmet_report_zone_data *report_zone_data = data;
+	struct nvme_zone_descriptor *entries = report_zone_data->rz->entries;
+	struct nvmet_ns *ns = report_zone_data->ns;
+
+	entries[idx].zcap = nvmet_sect_to_lba(ns, z->capacity);
+	entries[idx].zslba = nvmet_sect_to_lba(ns, z->start);
+	entries[idx].wp = nvmet_sect_to_lba(ns, z->wp);
+	entries[idx].za = z->reset ? 1 << 2 : 0;
+	entries[idx].zt = z->type;
+	entries[idx].zs = z->cond << 4;
+
+	return 0;
+}
+
+void nvmet_bdev_execute_zone_mgmt_recv(struct nvmet_req *req)
+{
+	sector_t sect = nvmet_lba_to_sect(req->ns, req->cmd->zmr.slba);
+	u32 bufsize = (le32_to_cpu(req->cmd->zmr.numd) + 1) << 2;
+	struct nvmet_report_zone_data data = { .ns = req->ns };
+	unsigned int nr_zones;
+	int reported_zones;
+	u16 status;
+
+	nr_zones = (bufsize - sizeof(struct nvme_zone_report)) /
+			sizeof(struct nvme_zone_descriptor);
+
+	status = nvmet_bdev_zns_checks(req);
+	if (status)
+		goto out;
+
+	data.rz = __vmalloc(bufsize, GFP_KERNEL | __GFP_NORETRY | __GFP_ZERO);
+	if (!data.rz) {
+		status = NVME_SC_INTERNAL;
+		goto out;
+	}
+
+	reported_zones = blkdev_report_zones(req->ns->bdev, sect, nr_zones,
+					     nvmet_bdev_report_zone_cb,
+					     &data);
+	if (reported_zones < 0) {
+		status = NVME_SC_INTERNAL;
+		goto out_free_report_zones;
+	}
+
+	data.rz->nr_zones = cpu_to_le64(reported_zones);
+
+	status = nvmet_copy_to_sgl(req, 0, data.rz, bufsize);
+
+out_free_report_zones:
+	kvfree(data.rz);
+out:
+	nvmet_req_complete(req, status);
+}
+
+void nvmet_bdev_execute_zone_mgmt_send(struct nvmet_req *req)
+{
+	sector_t sect = nvmet_lba_to_sect(req->ns, req->cmd->zms.slba);
+	sector_t nr_sect = bdev_zone_sectors(req->ns->bdev);
+	u16 status = NVME_SC_SUCCESS;
+	enum req_opf op;
+	int ret;
+
+	if (req->cmd->zms.select_all)
+		nr_sect = get_capacity(req->ns->bdev->bd_disk);
+
+	switch (req->cmd->zms.zsa) {
+	case NVME_ZONE_OPEN:
+		op = REQ_OP_ZONE_OPEN;
+		break;
+	case NVME_ZONE_CLOSE:
+		op = REQ_OP_ZONE_CLOSE;
+		break;
+	case NVME_ZONE_FINISH:
+		op = REQ_OP_ZONE_FINISH;
+		break;
+	case NVME_ZONE_RESET:
+		op = REQ_OP_ZONE_RESET;
+		break;
+	default:
+		status = NVME_SC_INVALID_FIELD;
+		goto out;
+	}
+
+	ret = blkdev_zone_mgmt(req->ns->bdev, op, sect, nr_sect, GFP_KERNEL);
+	if (ret)
+		status = NVME_SC_INTERNAL;
+out:
+	nvmet_req_complete(req, status);
+}
+
+void nvmet_bdev_execute_zone_append(struct nvmet_req *req)
+{
+	sector_t sect = nvmet_lba_to_sect(req->ns, req->cmd->rw.slba);
+	struct request_queue *q = req->ns->bdev->bd_disk->queue;
+	unsigned int max_sects = queue_max_zone_append_sectors(q);
+	u16 status = NVME_SC_SUCCESS;
+	unsigned int total_len = 0;
+	struct scatterlist *sg;
+	int ret = 0, sg_cnt;
+	struct bio *bio;
+
+	if (!nvmet_check_transfer_len(req, nvmet_rw_data_len(req)))
+		return;
+
+	if (!req->sg_cnt) {
+		nvmet_req_complete(req, 0);
+		return;
+	}
+
+	if (req->transfer_len <= NVMET_MAX_INLINE_DATA_LEN) {
+		bio = &req->b.inline_bio;
+		bio_init(bio, req->inline_bvec, ARRAY_SIZE(req->inline_bvec));
+	} else {
+		bio = bio_alloc(GFP_KERNEL, req->sg_cnt);
+	}
+
+	bio_set_dev(bio, req->ns->bdev);
+	bio->bi_iter.bi_sector = sect;
+	bio->bi_opf = REQ_OP_ZONE_APPEND | REQ_SYNC | REQ_IDLE;
+	if (req->cmd->rw.control & cpu_to_le16(NVME_RW_FUA))
+		bio->bi_opf |= REQ_FUA;
+
+	for_each_sg(req->sg, sg, req->sg_cnt, sg_cnt) {
+		struct page *p = sg_page(sg);
+		unsigned int l = sg->length;
+		unsigned int o = sg->offset;
+		bool same_page = false;
+
+		ret = bio_add_hw_page(q, bio, p, l, o, max_sects, &same_page);
+		if (ret != sg->length) {
+			status = NVME_SC_INTERNAL;
+			goto out_bio_put;
+		}
+		if (same_page)
+			put_page(p);
+
+		total_len += sg->length;
+	}
+
+	if (total_len != nvmet_rw_data_len(req)) {
+		status = NVME_SC_INTERNAL | NVME_SC_DNR;
+		goto out_bio_put;
+	}
+
+	ret = submit_bio_wait(bio);
+	req->cqe->result.u64 = nvmet_sect_to_lba(req->ns,
+						 bio->bi_iter.bi_sector);
+
+out_bio_put:
+	if (bio != &req->b.inline_bio)
+		bio_put(bio);
+	nvmet_req_complete(req, ret < 0 ? NVME_SC_INTERNAL : status);
+}
-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Mon Jan 11 23:26:19 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Mon, 11 Jan 2021 20:26:19 -0800
Subject: [PATCH V9 5/9] nvmet: add bio get helper for different backends
In-Reply-To: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210112042623.6316-6-chaitanya.kulkarni@wdc.com>

With the addition of the zns backend now we have three different
backends with inline bio optimization. That leads to having duplicate
code for allocating or initializing the bio in all three backends:
generic bdev, passsthru, and generic zns.

Add a helper function to reduce the duplicate code such that helper
function accepts the bi_end_io callback which gets initialize for the
non-inline bio_alloc() case. This is due to the special case needed for
the passthru backend non-inline bio allocation bio_alloc() where we set
the bio->bi_end_io = bio_put, having this parameter avoids the extra
branch in the passthru fast path. For rest of the backends, we set the
same bi_end_io callback for inline and non-inline cases, that is for
generic bdev we set to nvmet_bio_done() and for generic zns we set to
NULL. ? ? ? ? ? ? ? ? ? ? ? ? ? ?

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/target/io-cmd-bdev.c |  7 +------
 drivers/nvme/target/nvmet.h       | 16 ++++++++++++++++
 drivers/nvme/target/passthru.c    |  8 +-------
 drivers/nvme/target/zns.c         |  8 +-------
 4 files changed, 19 insertions(+), 20 deletions(-)

diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
index 6178ef643962..72746e29cb0d 100644
--- a/drivers/nvme/target/io-cmd-bdev.c
+++ b/drivers/nvme/target/io-cmd-bdev.c
@@ -266,12 +266,7 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req)
 
 	sector = nvmet_lba_to_sect(req->ns, req->cmd->rw.slba);
 
-	if (req->transfer_len <= NVMET_MAX_INLINE_DATA_LEN) {
-		bio = &req->b.inline_bio;
-		bio_init(bio, req->inline_bvec, ARRAY_SIZE(req->inline_bvec));
-	} else {
-		bio = bio_alloc(GFP_KERNEL, min(sg_cnt, BIO_MAX_PAGES));
-	}
+	bio = nvmet_req_bio_get(req, NULL);
 	bio_set_dev(bio, req->ns->bdev);
 	bio->bi_iter.bi_sector = sector;
 	bio->bi_private = req;
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 7361665585a2..3fc84f79cce1 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -652,4 +652,20 @@ nvmet_bdev_execute_zone_append(struct nvmet_req *req)
 }
 #endif /* CONFIG_BLK_DEV_ZONED */
 
+static inline struct bio *nvmet_req_bio_get(struct nvmet_req *req,
+					    bio_end_io_t *bi_end_io)
+{
+	struct bio *bio;
+
+	if (req->transfer_len <= NVMET_MAX_INLINE_DATA_LEN) {
+		bio = &req->b.inline_bio;
+		bio_init(bio, req->inline_bvec, ARRAY_SIZE(req->inline_bvec));
+		return bio;
+	}
+
+	bio = bio_alloc(GFP_KERNEL, req->sg_cnt);
+	bio->bi_end_io = bi_end_io;
+	return bio;
+}
+
 #endif /* _NVMET_H */
diff --git a/drivers/nvme/target/passthru.c b/drivers/nvme/target/passthru.c
index b9776fc8f08f..54f765b566ee 100644
--- a/drivers/nvme/target/passthru.c
+++ b/drivers/nvme/target/passthru.c
@@ -194,13 +194,7 @@ static int nvmet_passthru_map_sg(struct nvmet_req *req, struct request *rq)
 	if (req->sg_cnt > BIO_MAX_PAGES)
 		return -EINVAL;
 
-	if (req->transfer_len <= NVMET_MAX_INLINE_DATA_LEN) {
-		bio = &req->p.inline_bio;
-		bio_init(bio, req->inline_bvec, ARRAY_SIZE(req->inline_bvec));
-	} else {
-		bio = bio_alloc(GFP_KERNEL, min(req->sg_cnt, BIO_MAX_PAGES));
-		bio->bi_end_io = bio_put;
-	}
+	bio = nvmet_req_bio_get(req, bio_put);
 	bio->bi_opf = req_op(rq);
 
 	for_each_sg(req->sg, sg, req->sg_cnt, i) {
diff --git a/drivers/nvme/target/zns.c b/drivers/nvme/target/zns.c
index 2a71f56e568d..c32e93a3c7e1 100644
--- a/drivers/nvme/target/zns.c
+++ b/drivers/nvme/target/zns.c
@@ -296,13 +296,7 @@ void nvmet_bdev_execute_zone_append(struct nvmet_req *req)
 		return;
 	}
 
-	if (req->transfer_len <= NVMET_MAX_INLINE_DATA_LEN) {
-		bio = &req->b.inline_bio;
-		bio_init(bio, req->inline_bvec, ARRAY_SIZE(req->inline_bvec));
-	} else {
-		bio = bio_alloc(GFP_KERNEL, req->sg_cnt);
-	}
-
+	bio = nvmet_req_bio_get(req, NULL);
 	bio_set_dev(bio, req->ns->bdev);
 	bio->bi_iter.bi_sector = sect;
 	bio->bi_opf = REQ_OP_ZONE_APPEND | REQ_SYNC | REQ_IDLE;
-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Mon Jan 11 23:26:20 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Mon, 11 Jan 2021 20:26:20 -0800
Subject: [PATCH V9 6/9] nvmet: add bio init helper for different backends
In-Reply-To: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210112042623.6316-7-chaitanya.kulkarni@wdc.com>

With the addition of the zns backend now we have two different backends
with the same bio initialization code. That leads to having duplicate
code in two backends: generic bdev and generic zns.

Add a helper function to reduce the duplicate code such that helper
function initializes the various bio initialization parameters such as
bio block device, op flags, sector, end io callback, and private member,

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/target/io-cmd-bdev.c |  6 +-----
 drivers/nvme/target/nvmet.h       | 11 +++++++++++
 drivers/nvme/target/zns.c         |  6 +++---
 3 files changed, 15 insertions(+), 8 deletions(-)

diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
index 72746e29cb0d..b1fb0bb1f39f 100644
--- a/drivers/nvme/target/io-cmd-bdev.c
+++ b/drivers/nvme/target/io-cmd-bdev.c
@@ -267,11 +267,7 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req)
 	sector = nvmet_lba_to_sect(req->ns, req->cmd->rw.slba);
 
 	bio = nvmet_req_bio_get(req, NULL);
-	bio_set_dev(bio, req->ns->bdev);
-	bio->bi_iter.bi_sector = sector;
-	bio->bi_private = req;
-	bio->bi_end_io = nvmet_bio_done;
-	bio->bi_opf = op;
+	nvmet_bio_init(bio, req->ns->bdev, op, sector, req, nvmet_bio_done);
 
 	blk_start_plug(&plug);
 	if (req->metadata_len)
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 3fc84f79cce1..1ec9e1b35c67 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -668,4 +668,15 @@ static inline struct bio *nvmet_req_bio_get(struct nvmet_req *req,
 	return bio;
 }
 
+static inline void nvmet_bio_init(struct bio *bio, struct block_device *bdev,
+				  unsigned int op, sector_t sect, void *private,
+				  bio_end_io_t *bi_end_io)
+{
+	bio_set_dev(bio, bdev);
+	bio->bi_opf = op;
+	bio->bi_iter.bi_sector = sect;
+	bio->bi_private = private;
+	bio->bi_end_io = bi_end_io;
+}
+
 #endif /* _NVMET_H */
diff --git a/drivers/nvme/target/zns.c b/drivers/nvme/target/zns.c
index c32e93a3c7e1..92213bed0006 100644
--- a/drivers/nvme/target/zns.c
+++ b/drivers/nvme/target/zns.c
@@ -281,6 +281,7 @@ void nvmet_bdev_execute_zone_append(struct nvmet_req *req)
 {
 	sector_t sect = nvmet_lba_to_sect(req->ns, req->cmd->rw.slba);
 	struct request_queue *q = req->ns->bdev->bd_disk->queue;
+	unsigned int op = REQ_OP_ZONE_APPEND | REQ_SYNC | REQ_IDLE;
 	unsigned int max_sects = queue_max_zone_append_sectors(q);
 	u16 status = NVME_SC_SUCCESS;
 	unsigned int total_len = 0;
@@ -297,9 +298,8 @@ void nvmet_bdev_execute_zone_append(struct nvmet_req *req)
 	}
 
 	bio = nvmet_req_bio_get(req, NULL);
-	bio_set_dev(bio, req->ns->bdev);
-	bio->bi_iter.bi_sector = sect;
-	bio->bi_opf = REQ_OP_ZONE_APPEND | REQ_SYNC | REQ_IDLE;
+	nvmet_bio_init(bio, req->ns->bdev, op, sect, NULL, NULL);
+
 	if (req->cmd->rw.control & cpu_to_le16(NVME_RW_FUA))
 		bio->bi_opf |= REQ_FUA;
 
-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Mon Jan 11 23:26:21 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Mon, 11 Jan 2021 20:26:21 -0800
Subject: [PATCH V9 7/9] nvmet: add bio put helper for different backends
In-Reply-To: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210112042623.6316-8-chaitanya.kulkarni@wdc.com>

With the addition of zns backend now we have three different backends
with inline bio optimization. That leads to having duplicate code in for
freeing the bio in all three backends: generic bdev, passsthru and
generic zns.

Add a helper function to avoid the duplicate code and update the
respective backends.

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/target/io-cmd-bdev.c | 3 +--
 drivers/nvme/target/nvmet.h       | 6 ++++++
 drivers/nvme/target/passthru.c    | 3 +--
 drivers/nvme/target/zns.c         | 3 +--
 4 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
index b1fb0bb1f39f..562c2dd9c08c 100644
--- a/drivers/nvme/target/io-cmd-bdev.c
+++ b/drivers/nvme/target/io-cmd-bdev.c
@@ -172,8 +172,7 @@ static void nvmet_bio_done(struct bio *bio)
 	struct nvmet_req *req = bio->bi_private;
 
 	nvmet_req_complete(req, blk_to_nvme_status(req, bio->bi_status));
-	if (bio != &req->b.inline_bio)
-		bio_put(bio);
+	nvmet_req_bio_put(req, bio);
 }
 
 #ifdef CONFIG_BLK_DEV_INTEGRITY
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 1ec9e1b35c67..93ebc9ae3fe4 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -679,4 +679,10 @@ static inline void nvmet_bio_init(struct bio *bio, struct block_device *bdev,
 	bio->bi_end_io = bi_end_io;
 }
 
+static inline void nvmet_req_bio_put(struct nvmet_req *req, struct bio *bio)
+{
+	if (bio != &req->b.inline_bio)
+		bio_put(bio);
+}
+
 #endif /* _NVMET_H */
diff --git a/drivers/nvme/target/passthru.c b/drivers/nvme/target/passthru.c
index 54f765b566ee..a4a73d64c603 100644
--- a/drivers/nvme/target/passthru.c
+++ b/drivers/nvme/target/passthru.c
@@ -200,8 +200,7 @@ static int nvmet_passthru_map_sg(struct nvmet_req *req, struct request *rq)
 	for_each_sg(req->sg, sg, req->sg_cnt, i) {
 		if (bio_add_pc_page(rq->q, bio, sg_page(sg), sg->length,
 				    sg->offset) < sg->length) {
-			if (bio != &req->p.inline_bio)
-				bio_put(bio);
+			nvmet_req_bio_put(req, bio);
 			return -EINVAL;
 		}
 	}
diff --git a/drivers/nvme/target/zns.c b/drivers/nvme/target/zns.c
index 92213bed0006..bba1d6957b6a 100644
--- a/drivers/nvme/target/zns.c
+++ b/drivers/nvme/target/zns.c
@@ -330,7 +330,6 @@ void nvmet_bdev_execute_zone_append(struct nvmet_req *req)
 						 bio->bi_iter.bi_sector);
 
 out_bio_put:
-	if (bio != &req->b.inline_bio)
-		bio_put(bio);
+	nvmet_req_bio_put(req, bio);
 	nvmet_req_complete(req, ret < 0 ? NVME_SC_INTERNAL : status);
 }
-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Mon Jan 11 23:26:22 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Mon, 11 Jan 2021 20:26:22 -0800
Subject: [PATCH V9 8/9] nvmet: add common I/O length check helper
In-Reply-To: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210112042623.6316-9-chaitanya.kulkarni@wdc.com>

With the addition of zns backend now we have three different backends
with which checks for the nvmet request's transfer len and nvmet
request's sg_cnt. That leads to having duplicate code in for three
backends: generic bdev, file and generic zns.

Add a helper function to avoid the duplicate code and update the
respective backends.

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/target/io-cmd-bdev.c |  8 +-------
 drivers/nvme/target/io-cmd-file.c |  7 +------
 drivers/nvme/target/nvmet.h       | 14 ++++++++++++++
 drivers/nvme/target/zns.c         |  7 +------
 4 files changed, 17 insertions(+), 19 deletions(-)

diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
index 562c2dd9c08c..c23a719513b0 100644
--- a/drivers/nvme/target/io-cmd-bdev.c
+++ b/drivers/nvme/target/io-cmd-bdev.c
@@ -240,16 +240,10 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req)
 	int op, i, rc;
 	struct sg_mapping_iter prot_miter;
 	unsigned int iter_flags;
-	unsigned int total_len = nvmet_rw_data_len(req) + req->metadata_len;
 
-	if (!nvmet_check_transfer_len(req, total_len))
+	if (!nvmet_continue_io(req, nvmet_rw_data_len(req) + req->metadata_len))
 		return;
 
-	if (!req->sg_cnt) {
-		nvmet_req_complete(req, 0);
-		return;
-	}
-
 	if (req->cmd->rw.opcode == nvme_cmd_write) {
 		op = REQ_OP_WRITE | REQ_SYNC | REQ_IDLE;
 		if (req->cmd->rw.control & cpu_to_le16(NVME_RW_FUA))
diff --git a/drivers/nvme/target/io-cmd-file.c b/drivers/nvme/target/io-cmd-file.c
index 0abbefd9925e..e7caff221b7b 100644
--- a/drivers/nvme/target/io-cmd-file.c
+++ b/drivers/nvme/target/io-cmd-file.c
@@ -241,14 +241,9 @@ static void nvmet_file_execute_rw(struct nvmet_req *req)
 {
 	ssize_t nr_bvec = req->sg_cnt;
 
-	if (!nvmet_check_transfer_len(req, nvmet_rw_data_len(req)))
+	if (!nvmet_continue_io(req, nvmet_rw_data_len(req)))
 		return;
 
-	if (!req->sg_cnt || !nr_bvec) {
-		nvmet_req_complete(req, 0);
-		return;
-	}
-
 	if (nr_bvec > NVMET_MAX_INLINE_BIOVEC)
 		req->f.bvec = kmalloc_array(nr_bvec, sizeof(struct bio_vec),
 				GFP_KERNEL);
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 93ebc9ae3fe4..f4f9d622df0d 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -685,4 +685,18 @@ static inline void nvmet_req_bio_put(struct nvmet_req *req, struct bio *bio)
 		bio_put(bio);
 }
 
+static inline bool nvmet_continue_io(struct nvmet_req *req,
+				     unsigned int total_len)
+{
+	if (!nvmet_check_transfer_len(req, total_len))
+		return false;
+
+	if (!req->sg_cnt) {
+		nvmet_req_complete(req, 0);
+		return false;
+	}
+
+	return true;
+}
+
 #endif /* _NVMET_H */
diff --git a/drivers/nvme/target/zns.c b/drivers/nvme/target/zns.c
index bba1d6957b6a..149bc8ce7010 100644
--- a/drivers/nvme/target/zns.c
+++ b/drivers/nvme/target/zns.c
@@ -289,14 +289,9 @@ void nvmet_bdev_execute_zone_append(struct nvmet_req *req)
 	int ret = 0, sg_cnt;
 	struct bio *bio;
 
-	if (!nvmet_check_transfer_len(req, nvmet_rw_data_len(req)))
+	if (!nvmet_continue_io(req, nvmet_rw_data_len(req)))
 		return;
 
-	if (!req->sg_cnt) {
-		nvmet_req_complete(req, 0);
-		return;
-	}
-
 	bio = nvmet_req_bio_get(req, NULL);
 	nvmet_bio_init(bio, req->ns->bdev, op, sect, NULL, NULL);
 
-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Mon Jan 11 23:26:23 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Mon, 11 Jan 2021 20:26:23 -0800
Subject: [PATCH V9 9/9] nvmet: call nvmet_bio_done() for zone append
In-Reply-To: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210112042623.6316-10-chaitanya.kulkarni@wdc.com>

The function nvmet_bdev_execute_zone_append() does exactly same thing
for completion of the bio that is done in the nvmet_bio_done(),
completing the request & calling nvmet_bio_put()_to put non online bio.

Export the function nvmet_bio_done() and use that in the
nvmet_bdev_execute_zone_append() for the request completion and bio
processing. Set the bio->private after the call to submit_bio_wait() to
nvmet request. The call to nvmet_bio_done() also updates error log page
via call to blk_to_nvme_status() from nvmet_bio_done().

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/target/io-cmd-bdev.c |  2 +-
 drivers/nvme/target/nvmet.h       |  1 +
 drivers/nvme/target/zns.c         | 10 ++++------
 3 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
index c23a719513b0..72a22351da2a 100644
--- a/drivers/nvme/target/io-cmd-bdev.c
+++ b/drivers/nvme/target/io-cmd-bdev.c
@@ -167,7 +167,7 @@ static u16 blk_to_nvme_status(struct nvmet_req *req, blk_status_t blk_sts)
 	return status;
 }
 
-static void nvmet_bio_done(struct bio *bio)
+void nvmet_bio_done(struct bio *bio)
 {
 	struct nvmet_req *req = bio->bi_private;
 
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index f4f9d622df0d..ab84ab75b952 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -535,6 +535,7 @@ void nvmet_ns_changed(struct nvmet_subsys *subsys, u32 nsid);
 void nvmet_bdev_ns_revalidate(struct nvmet_ns *ns);
 int nvmet_file_ns_revalidate(struct nvmet_ns *ns);
 void nvmet_ns_revalidate(struct nvmet_ns *ns);
+void nvmet_bio_done(struct bio *bio);
 
 static inline u32 nvmet_rw_data_len(struct nvmet_req *req)
 {
diff --git a/drivers/nvme/target/zns.c b/drivers/nvme/target/zns.c
index 149bc8ce7010..da4be0231428 100644
--- a/drivers/nvme/target/zns.c
+++ b/drivers/nvme/target/zns.c
@@ -283,7 +283,6 @@ void nvmet_bdev_execute_zone_append(struct nvmet_req *req)
 	struct request_queue *q = req->ns->bdev->bd_disk->queue;
 	unsigned int op = REQ_OP_ZONE_APPEND | REQ_SYNC | REQ_IDLE;
 	unsigned int max_sects = queue_max_zone_append_sectors(q);
-	u16 status = NVME_SC_SUCCESS;
 	unsigned int total_len = 0;
 	struct scatterlist *sg;
 	int ret = 0, sg_cnt;
@@ -306,7 +305,7 @@ void nvmet_bdev_execute_zone_append(struct nvmet_req *req)
 
 		ret = bio_add_hw_page(q, bio, p, l, o, max_sects, &same_page);
 		if (ret != sg->length) {
-			status = NVME_SC_INTERNAL;
+			bio->bi_status = BLK_STS_IOERR;
 			goto out_bio_put;
 		}
 		if (same_page)
@@ -316,15 +315,14 @@ void nvmet_bdev_execute_zone_append(struct nvmet_req *req)
 	}
 
 	if (total_len != nvmet_rw_data_len(req)) {
-		status = NVME_SC_INTERNAL | NVME_SC_DNR;
+		bio->bi_status = BLK_STS_IOERR;
 		goto out_bio_put;
 	}
 
 	ret = submit_bio_wait(bio);
 	req->cqe->result.u64 = nvmet_sect_to_lba(req->ns,
 						 bio->bi_iter.bi_sector);
-
 out_bio_put:
-	nvmet_req_bio_put(req, bio);
-	nvmet_req_complete(req, ret < 0 ? NVME_SC_INTERNAL : status);
+	bio->bi_private = req;
+	nvmet_bio_done(bio);
 }
-- 
2.22.1



From Damien.LeMoal at wdc.com  Tue Jan 12 00:08:32 2021
From: Damien.LeMoal at wdc.com (Damien Le Moal)
Date: Tue, 12 Jan 2021 05:08:32 +0000
Subject: [PATCH V9 2/9] nvmet: add lba to sect conversion helpers
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-3-chaitanya.kulkarni@wdc.com>
Message-ID: <BL0PR04MB6514DAF27FFAAB70FED4B0B8E7AA0@BL0PR04MB6514.namprd04.prod.outlook.com>

On 2021/01/12 13:26, Chaitanya Kulkarni wrote:
> In this preparation patch, we add helpers to convert lbas to sectors &
> sectors to lba. This is needed to eliminate code duplication in the ZBD
> backend.
> 
> Use these helpers in the block device backend.
> 
> Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
> ---
>  drivers/nvme/target/io-cmd-bdev.c |  8 +++-----
>  drivers/nvme/target/nvmet.h       | 10 ++++++++++
>  2 files changed, 13 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
> index 125dde3f410e..23095bdfce06 100644
> --- a/drivers/nvme/target/io-cmd-bdev.c
> +++ b/drivers/nvme/target/io-cmd-bdev.c
> @@ -256,8 +256,7 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req)
>  	if (is_pci_p2pdma_page(sg_page(req->sg)))
>  		op |= REQ_NOMERGE;
>  
> -	sector = le64_to_cpu(req->cmd->rw.slba);
> -	sector <<= (req->ns->blksize_shift - 9);
> +	sector = nvmet_lba_to_sect(req->ns, req->cmd->rw.slba);
>  
>  	if (req->transfer_len <= NVMET_MAX_INLINE_DATA_LEN) {
>  		bio = &req->b.inline_bio;
> @@ -345,7 +344,7 @@ static u16 nvmet_bdev_discard_range(struct nvmet_req *req,
>  	int ret;
>  
>  	ret = __blkdev_issue_discard(ns->bdev,
> -			le64_to_cpu(range->slba) << (ns->blksize_shift - 9),
> +			nvmet_lba_to_sect(ns, range->slba),
>  			le32_to_cpu(range->nlb) << (ns->blksize_shift - 9),
>  			GFP_KERNEL, 0, bio);
>  	if (ret && ret != -EOPNOTSUPP) {
> @@ -414,8 +413,7 @@ static void nvmet_bdev_execute_write_zeroes(struct nvmet_req *req)
>  	if (!nvmet_check_transfer_len(req, 0))
>  		return;
>  
> -	sector = le64_to_cpu(write_zeroes->slba) <<
> -		(req->ns->blksize_shift - 9);
> +	sector = nvmet_lba_to_sect(req->ns, write_zeroes->slba);
>  	nr_sector = (((sector_t)le16_to_cpu(write_zeroes->length) + 1) <<
>  		(req->ns->blksize_shift - 9));
>  
> diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
> index 592763732065..8776dd1a0490 100644
> --- a/drivers/nvme/target/nvmet.h
> +++ b/drivers/nvme/target/nvmet.h
> @@ -603,4 +603,14 @@ static inline bool nvmet_ns_has_pi(struct nvmet_ns *ns)
>  	return ns->pi_type && ns->metadata_size == sizeof(struct t10_pi_tuple);
>  }
>  
> +static inline __le64 nvmet_sect_to_lba(struct nvmet_ns *ns, sector_t sect)
> +{
> +	return cpu_to_le64(sect >> (ns->blksize_shift - SECTOR_SHIFT));
> +}
> +
> +static inline sector_t nvmet_lba_to_sect(struct nvmet_ns *ns, __le64 lba)
> +{
> +	return le64_to_cpu(lba) << (ns->blksize_shift - SECTOR_SHIFT);
> +}
> +
>  #endif /* _NVMET_H */
> 

Looks good.

Reviewed-by: Damien Le Moal <damien.lemoal at wdc.com>

-- 
Damien Le Moal
Western Digital Research


From Damien.LeMoal at wdc.com  Tue Jan 12 00:32:48 2021
From: Damien.LeMoal at wdc.com (Damien Le Moal)
Date: Tue, 12 Jan 2021 05:32:48 +0000
Subject: [PATCH V9 4/9] nvmet: add ZBD over ZNS backend support
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-5-chaitanya.kulkarni@wdc.com>
Message-ID: <BL0PR04MB6514A4C7F0F7A2627C4639B3E7AA0@BL0PR04MB6514.namprd04.prod.outlook.com>

On 2021/01/12 13:27, Chaitanya Kulkarni wrote:
> NVMe TP 4053 ? Zoned Namespaces (ZNS) allows host software to
> communicate with a non-volatile memory subsystem using zones for
> NVMe protocol based controllers. NVMeOF already support the ZNS NVMe
> Protocol compliant devices on the target in the passthru mode. There
> are Generic zoned block devices like  Shingled Magnetic Recording (SMR)
> HDDs that are not based on the NVMe protocol.
> 
> This patch adds ZNS backend to support the ZBDs for NVMeOF target.
> 
> This support includes implementing the new command set NVME_CSI_ZNS,
> adding different command handlers for ZNS command set such as
> NVMe Identify Controller, NVMe Identify Namespace, NVMe Zone Append,
> NVMe Zone Management Send and NVMe Zone Management Receive.
> 
> With new command set identifier we also update the target command effects
> logs to reflect the ZNS compliant commands.
> 
> Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
> ---
>  drivers/nvme/target/Makefile      |   1 +
>  drivers/nvme/target/admin-cmd.c   |  28 +++
>  drivers/nvme/target/core.c        |   3 +
>  drivers/nvme/target/io-cmd-bdev.c |  33 ++-
>  drivers/nvme/target/nvmet.h       |  38 ++++
>  drivers/nvme/target/zns.c         | 342 ++++++++++++++++++++++++++++++
>  6 files changed, 437 insertions(+), 8 deletions(-)
>  create mode 100644 drivers/nvme/target/zns.c
> 
> diff --git a/drivers/nvme/target/Makefile b/drivers/nvme/target/Makefile
> index ebf91fc4c72e..9837e580fa7e 100644
> --- a/drivers/nvme/target/Makefile
> +++ b/drivers/nvme/target/Makefile
> @@ -12,6 +12,7 @@ obj-$(CONFIG_NVME_TARGET_TCP)		+= nvmet-tcp.o
>  nvmet-y		+= core.o configfs.o admin-cmd.o fabrics-cmd.o \
>  			discovery.o io-cmd-file.o io-cmd-bdev.o
>  nvmet-$(CONFIG_NVME_TARGET_PASSTHRU)	+= passthru.o
> +nvmet-$(CONFIG_BLK_DEV_ZONED)		+= zns.o
>  nvme-loop-y	+= loop.o
>  nvmet-rdma-y	+= rdma.o
>  nvmet-fc-y	+= fc.o
> diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
> index a50b7bcac67a..bdf09d8faa48 100644
> --- a/drivers/nvme/target/admin-cmd.c
> +++ b/drivers/nvme/target/admin-cmd.c
> @@ -191,6 +191,15 @@ static void nvmet_execute_get_log_cmd_effects_ns(struct nvmet_req *req)
>  		log->iocs[nvme_cmd_dsm]			= cpu_to_le32(1 << 0);
>  		log->iocs[nvme_cmd_write_zeroes]	= cpu_to_le32(1 << 0);
>  		break;
> +	case NVME_CSI_ZNS:
> +		if (IS_ENABLED(CONFIG_BLK_DEV_ZONED)) {
> +			u32 *iocs = log->iocs;
> +
> +			iocs[nvme_cmd_zone_append]	= cpu_to_le32(1 << 0);
> +			iocs[nvme_cmd_zone_mgmt_send]	= cpu_to_le32(1 << 0);
> +			iocs[nvme_cmd_zone_mgmt_recv]	= cpu_to_le32(1 << 0);
> +		}

Is it OK to not return an error here if CONFIG_BLK_DEV_ZONED is not enabled ?
I have not checked the entire code of this function nor how it is called, so I
may be wrong.

> +		break;
>  	default:
>  		status = NVME_SC_INVALID_LOG_PAGE;
>  		break;
> @@ -644,6 +653,17 @@ static void nvmet_execute_identify_desclist(struct nvmet_req *req)
>  	if (status)
>  		goto out;
>  
> +	if (IS_ENABLED(CONFIG_BLK_DEV_ZONED)) {
> +		u16 nvme_cis_zns = NVME_CSI_ZNS;
> +
> +		if (req->ns->csi == NVME_CSI_ZNS)
> +			status = nvmet_copy_ns_identifier(req, NVME_NIDT_CSI,
> +							  NVME_NIDT_CSI_LEN,
> +							  &nvme_cis_zns, &off);
> +		if (status)
> +			goto out;
> +	}

Same comment here.

> +
>  	if (sg_zero_buffer(req->sg, req->sg_cnt, NVME_IDENTIFY_DATA_SIZE - off,
>  			off) != NVME_IDENTIFY_DATA_SIZE - off)
>  		status = NVME_SC_INTERNAL | NVME_SC_DNR;
> @@ -660,8 +680,16 @@ static void nvmet_execute_identify(struct nvmet_req *req)
>  	switch (req->cmd->identify.cns) {
>  	case NVME_ID_CNS_NS:
>  		return nvmet_execute_identify_ns(req);
> +	case NVME_ID_CNS_CS_NS:
> +		if (req->cmd->identify.csi == NVME_CSI_ZNS)
> +			return nvmet_execute_identify_cns_cs_ns(req);
> +		break;
>  	case NVME_ID_CNS_CTRL:
>  		return nvmet_execute_identify_ctrl(req);
> +	case NVME_ID_CNS_CS_CTRL:
> +		if (req->cmd->identify.csi == NVME_CSI_ZNS)
> +			return nvmet_execute_identify_cns_cs_ctrl(req);
> +		break;
>  	case NVME_ID_CNS_NS_ACTIVE_LIST:
>  		return nvmet_execute_identify_nslist(req);
>  	case NVME_ID_CNS_NS_DESC_LIST:
> diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
> index 672e4009f8d6..17d5da062a5a 100644
> --- a/drivers/nvme/target/core.c
> +++ b/drivers/nvme/target/core.c
> @@ -1107,6 +1107,7 @@ static inline u8 nvmet_cc_iocqes(u32 cc)
>  static inline bool nvmet_cc_css_check(u8 cc_css)
>  {
>  	switch (cc_css <<= NVME_CC_CSS_SHIFT) {
> +	case NVME_CC_CSS_CSI:
>  	case NVME_CC_CSS_NVM:
>  		return true;
>  	default:
> @@ -1173,6 +1174,8 @@ static void nvmet_init_cap(struct nvmet_ctrl *ctrl)
>  {
>  	/* command sets supported: NVMe command set: */
>  	ctrl->cap = (1ULL << 37);
> +	if (IS_ENABLED(CONFIG_BLK_DEV_ZONED))
> +		ctrl->cap |= (1ULL << 43);
>  	/* CC.EN timeout in 500msec units: */
>  	ctrl->cap |= (15ULL << 24);
>  	/* maximum queue entries supported: */
> diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
> index 23095bdfce06..6178ef643962 100644
> --- a/drivers/nvme/target/io-cmd-bdev.c
> +++ b/drivers/nvme/target/io-cmd-bdev.c
> @@ -63,6 +63,14 @@ static void nvmet_bdev_ns_enable_integrity(struct nvmet_ns *ns)
>  	}
>  }
>  
> +void nvmet_bdev_ns_disable(struct nvmet_ns *ns)
> +{
> +	if (ns->bdev) {
> +		blkdev_put(ns->bdev, FMODE_WRITE | FMODE_READ);
> +		ns->bdev = NULL;
> +	}
> +}
> +
>  int nvmet_bdev_ns_enable(struct nvmet_ns *ns)
>  {
>  	int ret;
> @@ -86,15 +94,15 @@ int nvmet_bdev_ns_enable(struct nvmet_ns *ns)
>  	if (IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY_T10))
>  		nvmet_bdev_ns_enable_integrity(ns);
>  
> -	return 0;
> -}
> -
> -void nvmet_bdev_ns_disable(struct nvmet_ns *ns)
> -{
> -	if (ns->bdev) {
> -		blkdev_put(ns->bdev, FMODE_WRITE | FMODE_READ);
> -		ns->bdev = NULL;
> +	if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) && bdev_is_zoned(ns->bdev)) {
> +		if (!nvmet_bdev_zns_enable(ns)) {
> +			nvmet_bdev_ns_disable(ns);
> +			return -EINVAL;
> +		}
> +		ns->csi = NVME_CSI_ZNS;
>  	}
> +
> +	return 0;
>  }
>  
>  void nvmet_bdev_ns_revalidate(struct nvmet_ns *ns)
> @@ -448,6 +456,15 @@ u16 nvmet_bdev_parse_io_cmd(struct nvmet_req *req)
>  	case nvme_cmd_write_zeroes:
>  		req->execute = nvmet_bdev_execute_write_zeroes;
>  		return 0;
> +	case nvme_cmd_zone_append:
> +		req->execute = nvmet_bdev_execute_zone_append;
> +		return 0;
> +	case nvme_cmd_zone_mgmt_recv:
> +		req->execute = nvmet_bdev_execute_zone_mgmt_recv;
> +		return 0;
> +	case nvme_cmd_zone_mgmt_send:
> +		req->execute = nvmet_bdev_execute_zone_mgmt_send;
> +		return 0;
>  	default:
>  		pr_err("unhandled cmd %d on qid %d\n", cmd->common.opcode,
>  		       req->sq->qid);
> diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
> index 476b3cd91c65..7361665585a2 100644
> --- a/drivers/nvme/target/nvmet.h
> +++ b/drivers/nvme/target/nvmet.h
> @@ -252,6 +252,10 @@ struct nvmet_subsys {
>  	unsigned int		admin_timeout;
>  	unsigned int		io_timeout;
>  #endif /* CONFIG_NVME_TARGET_PASSTHRU */
> +
> +#ifdef CONFIG_BLK_DEV_ZONED
> +	u8			zasl;
> +#endif /* CONFIG_BLK_DEV_ZONED */
>  };
>  
>  static inline struct nvmet_subsys *to_subsys(struct config_item *item)
> @@ -614,4 +618,38 @@ static inline sector_t nvmet_lba_to_sect(struct nvmet_ns *ns, __le64 lba)
>  	return le64_to_cpu(lba) << (ns->blksize_shift - SECTOR_SHIFT);
>  }
>  
> +#ifdef CONFIG_BLK_DEV_ZONED
> +bool nvmet_bdev_zns_enable(struct nvmet_ns *ns);
> +void nvmet_execute_identify_cns_cs_ctrl(struct nvmet_req *req);
> +void nvmet_execute_identify_cns_cs_ns(struct nvmet_req *req);
> +void nvmet_bdev_execute_zone_mgmt_recv(struct nvmet_req *req);
> +void nvmet_bdev_execute_zone_mgmt_send(struct nvmet_req *req);
> +void nvmet_bdev_execute_zone_append(struct nvmet_req *req);
> +#else  /* CONFIG_BLK_DEV_ZONED */
> +static inline bool nvmet_bdev_zns_enable(struct nvmet_ns *ns)
> +{
> +	return false;
> +}
> +static inline void
> +nvmet_execute_identify_cns_cs_ctrl(struct nvmet_req *req)
> +{
> +}
> +static inline void
> +nvmet_execute_identify_cns_cs_ns(struct nvmet_req *req)
> +{
> +}
> +static inline void
> +nvmet_bdev_execute_zone_mgmt_recv(struct nvmet_req *req)
> +{
> +}
> +static inline void
> +nvmet_bdev_execute_zone_mgmt_send(struct nvmet_req *req)
> +{
> +}
> +static inline void
> +nvmet_bdev_execute_zone_append(struct nvmet_req *req)
> +{
> +}
> +#endif /* CONFIG_BLK_DEV_ZONED */
> +
>  #endif /* _NVMET_H */
> diff --git a/drivers/nvme/target/zns.c b/drivers/nvme/target/zns.c
> new file mode 100644
> index 000000000000..2a71f56e568d
> --- /dev/null
> +++ b/drivers/nvme/target/zns.c
> @@ -0,0 +1,342 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * NVMe ZNS-ZBD command implementation.
> + * Copyright (c) 2020-2021 HGST, a Western Digital Company.
> + */
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +#include <linux/nvme.h>
> +#include <linux/blkdev.h>
> +#include "nvmet.h"
> +
> +/*
> + * We set the Memory Page Size Minimum (MPSMIN) for target controller to 0
> + * which gets added by 12 in the nvme_enable_ctrl() which results in 2^12 = 4k
> + * as page_shift value. When calculating the ZASL use shift by 12.
> + */
> +#define NVMET_MPSMIN_SHIFT	12
> +
> +static u16 nvmet_bdev_zns_checks(struct nvmet_req *req)
> +{
> +	u16 status = NVME_SC_SUCCESS;
> +
> +	if (!bdev_is_zoned(req->ns->bdev)) {
> +		status = NVME_SC_INVALID_NS | NVME_SC_DNR;
> +		goto out;
> +	}
> +
> +	if (req->cmd->zmr.zra != NVME_ZRA_ZONE_REPORT) {
> +		status = NVME_SC_INVALID_FIELD;
> +		goto out;
> +	}
> +
> +	if (req->cmd->zmr.zrasf != NVME_ZRASF_ZONE_REPORT_ALL) {
> +		status = NVME_SC_INVALID_FIELD;
> +		goto out;
> +	}
> +
> +	if (req->cmd->zmr.pr != NVME_REPORT_ZONE_PARTIAL)
> +		status = NVME_SC_INVALID_FIELD;
> +
> +out:

You really want to keep this (useless) label ? Without it, the status variable
can be dropped and the code overall becomes so much easier to read... Not to
mention that life will be easier to the compiler for optimizing this.

> +	return status;
> +}
> +
> +/*
> + *  ZNS related command implementation and helpers.
> + */
> +
> +static inline u8 nvmet_zasl(unsigned int zone_append_sects)
> +{
> +	/*
> +	 * Zone Append Size Limit is the value experessed in the units
> +	 * of minimum memory page size (i.e. 12) and is reported power of 2.
> +	 */
> +	return ilog2((zone_append_sects << 9) >> NVMET_MPSMIN_SHIFT);
> +}
> +
> +static inline bool nvmet_zns_update_zasl(struct nvmet_ns *ns)
> +{
> +	struct request_queue *q = ns->bdev->bd_disk->queue;
> +	u8 zasl = nvmet_zasl(queue_max_zone_append_sectors(q));
> +
> +	if (ns->subsys->zasl)
> +		return ns->subsys->zasl < zasl ? false : true;
> +
> +	ns->subsys->zasl = zasl;
> +	return true;
> +}
> +
> +
> +static int nvmet_bdev_validate_zns_zones_cb(struct blk_zone *z,
> +					    unsigned int idx, void *data)
> +{
> +	if (z->type == BLK_ZONE_TYPE_CONVENTIONAL)
> +		return -EOPNOTSUPP;
> +	return 0;
> +}
> +
> +static bool nvmet_bdev_has_conv_zones(struct block_device *bdev)
> +{
> +	int ret;
> +
> +	if (bdev->bd_disk->queue->conv_zones_bitmap)
> +		return true;
> +
> +	ret = blkdev_report_zones(bdev, 0, blkdev_nr_zones(bdev->bd_disk),
> +				  nvmet_bdev_validate_zns_zones_cb, NULL);
> +
> +	return ret < 0 ? true : false;

return ret <= 0;

would be simpler.

Note that "<=" includes the error case of the device not reporting any zone
(device dead) as we should fail that case I think.

> +}
> +
> +bool nvmet_bdev_zns_enable(struct nvmet_ns *ns)
> +{
> +	if (nvmet_bdev_has_conv_zones(ns->bdev))
> +		return false;
> +
> +	/*
> +	 * For ZBC and ZAC devices, writes into sequential zones must be aligned
> +	 * to the device physical block size. So use this value as the logical
> +	 * block size to avoid errors.
> +	 */
> +	ns->blksize_shift = blksize_bits(bdev_physical_block_size(ns->bdev));
> +
> +	if (!nvmet_zns_update_zasl(ns))
> +		return false;
> +
> +	return !(get_capacity(ns->bdev->bd_disk) &
> +			(bdev_zone_sectors(ns->bdev) - 1));
> +}
> +
> +/*
> + * ZNS related Admin and I/O command handlers.
> + */
> +void nvmet_execute_identify_cns_cs_ctrl(struct nvmet_req *req)
> +{
> +	u8 zasl = req->sq->ctrl->subsys->zasl;
> +	struct nvmet_ctrl *ctrl = req->sq->ctrl;
> +	struct nvme_id_ctrl_zns *id;
> +	u16 status;
> +
> +	id = kzalloc(sizeof(*id), GFP_KERNEL);
> +	if (!id) {
> +		status = NVME_SC_INTERNAL;
> +		goto out;
> +	}
> +
> +	if (ctrl->ops->get_mdts)
> +		id->zasl = min_t(u8, ctrl->ops->get_mdts(ctrl), zasl);
> +	else
> +		id->zasl = zasl;
> +
> +	status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id));
> +
> +	kfree(id);
> +out:
> +	nvmet_req_complete(req, status);
> +}
> +
> +void nvmet_execute_identify_cns_cs_ns(struct nvmet_req *req)
> +{
> +	struct nvme_id_ns_zns *id_zns;
> +	u16 status = NVME_SC_SUCCESS;
> +	u64 zsze;
> +
> +	if (le32_to_cpu(req->cmd->identify.nsid) == NVME_NSID_ALL) {
> +		req->error_loc = offsetof(struct nvme_identify, nsid);
> +		status = NVME_SC_INVALID_NS | NVME_SC_DNR;
> +		goto out;
> +	}
> +
> +	id_zns = kzalloc(sizeof(*id_zns), GFP_KERNEL);
> +	if (!id_zns) {
> +		status = NVME_SC_INTERNAL;
> +		goto out;
> +	}
> +
> +	req->ns = nvmet_find_namespace(req->sq->ctrl, req->cmd->identify.nsid);
> +	if (!req->ns) {
> +		status = NVME_SC_INTERNAL;
> +		goto done;
> +	}
> +
> +	if (!bdev_is_zoned(req->ns->bdev)) {
> +		req->error_loc = offsetof(struct nvme_identify, nsid);
> +		status = NVME_SC_INVALID_NS | NVME_SC_DNR;
> +		goto done;
> +	}
> +
> +	nvmet_ns_revalidate(req->ns);
> +	zsze = (bdev_zone_sectors(req->ns->bdev) << 9) >>
> +					req->ns->blksize_shift;
> +	id_zns->lbafe[0].zsze = cpu_to_le64(zsze);
> +	id_zns->mor = cpu_to_le32(bdev_max_open_zones(req->ns->bdev));
> +	id_zns->mar = cpu_to_le32(bdev_max_active_zones(req->ns->bdev));
> +
> +done:
> +	status = nvmet_copy_to_sgl(req, 0, id_zns, sizeof(*id_zns));
> +	kfree(id_zns);
> +out:
> +	nvmet_req_complete(req, status);
> +}
> +
> +struct nvmet_report_zone_data {
> +	struct nvmet_ns *ns;
> +	struct nvme_zone_report *rz;
> +};
> +
> +static int nvmet_bdev_report_zone_cb(struct blk_zone *z, unsigned int idx,
> +				     void *data)
> +{
> +	struct nvmet_report_zone_data *report_zone_data = data;
> +	struct nvme_zone_descriptor *entries = report_zone_data->rz->entries;
> +	struct nvmet_ns *ns = report_zone_data->ns;
> +
> +	entries[idx].zcap = nvmet_sect_to_lba(ns, z->capacity);
> +	entries[idx].zslba = nvmet_sect_to_lba(ns, z->start);
> +	entries[idx].wp = nvmet_sect_to_lba(ns, z->wp);
> +	entries[idx].za = z->reset ? 1 << 2 : 0;
> +	entries[idx].zt = z->type;
> +	entries[idx].zs = z->cond << 4;
> +
> +	return 0;
> +}
> +
> +void nvmet_bdev_execute_zone_mgmt_recv(struct nvmet_req *req)
> +{
> +	sector_t sect = nvmet_lba_to_sect(req->ns, req->cmd->zmr.slba);
> +	u32 bufsize = (le32_to_cpu(req->cmd->zmr.numd) + 1) << 2;
> +	struct nvmet_report_zone_data data = { .ns = req->ns };
> +	unsigned int nr_zones;
> +	int reported_zones;
> +	u16 status;
> +
> +	nr_zones = (bufsize - sizeof(struct nvme_zone_report)) /
> +			sizeof(struct nvme_zone_descriptor);

I really would prefer this code to be moved down, before the call to
blkdev_report_zones().

You can also optimize this value a little with a min() of the value above and of
DIV_ROUND_UP(dev_capacity - sect, zone size). But not a big deal I think.

> +
> +	status = nvmet_bdev_zns_checks(req);
> +	if (status)
> +		goto out;
> +
> +	data.rz = __vmalloc(bufsize, GFP_KERNEL | __GFP_NORETRY | __GFP_ZERO);

Shouldn't this be GFP_NOIO ? Also, is the NORETRY critical ?
blkdev_report_zones() will do mem allocation too and at leadt scsi does retry.

> +	if (!data.rz) {
> +		status = NVME_SC_INTERNAL;
> +		goto out;
> +	}
> +
> +	reported_zones = blkdev_report_zones(req->ns->bdev, sect, nr_zones,
> +					     nvmet_bdev_report_zone_cb,
> +					     &data);
> +	if (reported_zones < 0) {
> +		status = NVME_SC_INTERNAL;
> +		goto out_free_report_zones;
> +	}
> +
> +	data.rz->nr_zones = cpu_to_le64(reported_zones);
> +
> +	status = nvmet_copy_to_sgl(req, 0, data.rz, bufsize);
> +
> +out_free_report_zones:
> +	kvfree(data.rz);
> +out:
> +	nvmet_req_complete(req, status);
> +}
> +
> +void nvmet_bdev_execute_zone_mgmt_send(struct nvmet_req *req)
> +{
> +	sector_t sect = nvmet_lba_to_sect(req->ns, req->cmd->zms.slba);
> +	sector_t nr_sect = bdev_zone_sectors(req->ns->bdev);
> +	u16 status = NVME_SC_SUCCESS;
> +	enum req_opf op;
> +	int ret;
> +
> +	if (req->cmd->zms.select_all)
> +		nr_sect = get_capacity(req->ns->bdev->bd_disk);
> +
> +	switch (req->cmd->zms.zsa) {
> +	case NVME_ZONE_OPEN:
> +		op = REQ_OP_ZONE_OPEN;
> +		break;
> +	case NVME_ZONE_CLOSE:
> +		op = REQ_OP_ZONE_CLOSE;
> +		break;
> +	case NVME_ZONE_FINISH:
> +		op = REQ_OP_ZONE_FINISH;
> +		break;
> +	case NVME_ZONE_RESET:
> +		op = REQ_OP_ZONE_RESET;
> +		break;
> +	default:
> +		status = NVME_SC_INVALID_FIELD;
> +		goto out;
> +	}
> +
> +	ret = blkdev_zone_mgmt(req->ns->bdev, op, sect, nr_sect, GFP_KERNEL);

GFP_NOIO ?

> +	if (ret)
> +		status = NVME_SC_INTERNAL;
> +out:
> +	nvmet_req_complete(req, status);
> +}
> +
> +void nvmet_bdev_execute_zone_append(struct nvmet_req *req)
> +{
> +	sector_t sect = nvmet_lba_to_sect(req->ns, req->cmd->rw.slba);
> +	struct request_queue *q = req->ns->bdev->bd_disk->queue;
> +	unsigned int max_sects = queue_max_zone_append_sectors(q);
> +	u16 status = NVME_SC_SUCCESS;
> +	unsigned int total_len = 0;
> +	struct scatterlist *sg;
> +	int ret = 0, sg_cnt;
> +	struct bio *bio;
> +
> +	if (!nvmet_check_transfer_len(req, nvmet_rw_data_len(req)))
> +		return;
> +
> +	if (!req->sg_cnt) {
> +		nvmet_req_complete(req, 0);
> +		return;
> +	}
> +
> +	if (req->transfer_len <= NVMET_MAX_INLINE_DATA_LEN) {
> +		bio = &req->b.inline_bio;
> +		bio_init(bio, req->inline_bvec, ARRAY_SIZE(req->inline_bvec));
> +	} else {
> +		bio = bio_alloc(GFP_KERNEL, req->sg_cnt);
> +	}
> +
> +	bio_set_dev(bio, req->ns->bdev);
> +	bio->bi_iter.bi_sector = sect;
> +	bio->bi_opf = REQ_OP_ZONE_APPEND | REQ_SYNC | REQ_IDLE;
> +	if (req->cmd->rw.control & cpu_to_le16(NVME_RW_FUA))
> +		bio->bi_opf |= REQ_FUA;
> +
> +	for_each_sg(req->sg, sg, req->sg_cnt, sg_cnt) {
> +		struct page *p = sg_page(sg);
> +		unsigned int l = sg->length;
> +		unsigned int o = sg->offset;
> +		bool same_page = false;
> +
> +		ret = bio_add_hw_page(q, bio, p, l, o, max_sects, &same_page);
> +		if (ret != sg->length) {
> +			status = NVME_SC_INTERNAL;
> +			goto out_bio_put;
> +		}
> +		if (same_page)
> +			put_page(p);
> +
> +		total_len += sg->length;
> +	}
> +
> +	if (total_len != nvmet_rw_data_len(req)) {
> +		status = NVME_SC_INTERNAL | NVME_SC_DNR;
> +		goto out_bio_put;
> +	}
> +
> +	ret = submit_bio_wait(bio);
> +	req->cqe->result.u64 = nvmet_sect_to_lba(req->ns,
> +						 bio->bi_iter.bi_sector);
> +
> +out_bio_put:
> +	if (bio != &req->b.inline_bio)
> +		bio_put(bio);
> +	nvmet_req_complete(req, ret < 0 ? NVME_SC_INTERNAL : status);
> +}
> 


-- 
Damien Le Moal
Western Digital Research


From Damien.LeMoal at wdc.com  Tue Jan 12 00:37:03 2021
From: Damien.LeMoal at wdc.com (Damien Le Moal)
Date: Tue, 12 Jan 2021 05:37:03 +0000
Subject: [PATCH V9 5/9] nvmet: add bio get helper for different backends
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-6-chaitanya.kulkarni@wdc.com>
Message-ID: <BL0PR04MB651444A9A810E0DA8D958431E7AA0@BL0PR04MB6514.namprd04.prod.outlook.com>

On 2021/01/12 13:27, Chaitanya Kulkarni wrote:
> With the addition of the zns backend now we have three different
> backends with inline bio optimization. That leads to having duplicate
> code for allocating or initializing the bio in all three backends:
> generic bdev, passsthru, and generic zns.
> 
> Add a helper function to reduce the duplicate code such that helper
> function accepts the bi_end_io callback which gets initialize for the
> non-inline bio_alloc() case. This is due to the special case needed for
> the passthru backend non-inline bio allocation bio_alloc() where we set
> the bio->bi_end_io = bio_put, having this parameter avoids the extra
> branch in the passthru fast path. For rest of the backends, we set the
> same bi_end_io callback for inline and non-inline cases, that is for
> generic bdev we set to nvmet_bio_done() and for generic zns we set to
> NULL. ? ? ? ? ? ? ? ? ? ? ? ? ? ?
> 
> Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
> ---
>  drivers/nvme/target/io-cmd-bdev.c |  7 +------
>  drivers/nvme/target/nvmet.h       | 16 ++++++++++++++++
>  drivers/nvme/target/passthru.c    |  8 +-------
>  drivers/nvme/target/zns.c         |  8 +-------
>  4 files changed, 19 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
> index 6178ef643962..72746e29cb0d 100644
> --- a/drivers/nvme/target/io-cmd-bdev.c
> +++ b/drivers/nvme/target/io-cmd-bdev.c
> @@ -266,12 +266,7 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req)
>  
>  	sector = nvmet_lba_to_sect(req->ns, req->cmd->rw.slba);
>  
> -	if (req->transfer_len <= NVMET_MAX_INLINE_DATA_LEN) {
> -		bio = &req->b.inline_bio;
> -		bio_init(bio, req->inline_bvec, ARRAY_SIZE(req->inline_bvec));
> -	} else {
> -		bio = bio_alloc(GFP_KERNEL, min(sg_cnt, BIO_MAX_PAGES));
> -	}
> +	bio = nvmet_req_bio_get(req, NULL);
>  	bio_set_dev(bio, req->ns->bdev);
>  	bio->bi_iter.bi_sector = sector;
>  	bio->bi_private = req;
> diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
> index 7361665585a2..3fc84f79cce1 100644
> --- a/drivers/nvme/target/nvmet.h
> +++ b/drivers/nvme/target/nvmet.h
> @@ -652,4 +652,20 @@ nvmet_bdev_execute_zone_append(struct nvmet_req *req)
>  }
>  #endif /* CONFIG_BLK_DEV_ZONED */
>  
> +static inline struct bio *nvmet_req_bio_get(struct nvmet_req *req,
> +					    bio_end_io_t *bi_end_io)
> +{
> +	struct bio *bio;
> +
> +	if (req->transfer_len <= NVMET_MAX_INLINE_DATA_LEN) {
> +		bio = &req->b.inline_bio;
> +		bio_init(bio, req->inline_bvec, ARRAY_SIZE(req->inline_bvec));
> +		return bio;
> +	}
> +
> +	bio = bio_alloc(GFP_KERNEL, req->sg_cnt);

I have a doubt about the use of GFP_KERNEL here... Shouldn't these be GFP_NOIO ?
The code was like this so it is may be OK, but without GFP_NOIO, is forward
progress guaranteed ? No recursion possible ?

> +	bio->bi_end_io = bi_end_io;
> +	return bio;
> +}
> +
>  #endif /* _NVMET_H */
> diff --git a/drivers/nvme/target/passthru.c b/drivers/nvme/target/passthru.c
> index b9776fc8f08f..54f765b566ee 100644
> --- a/drivers/nvme/target/passthru.c
> +++ b/drivers/nvme/target/passthru.c
> @@ -194,13 +194,7 @@ static int nvmet_passthru_map_sg(struct nvmet_req *req, struct request *rq)
>  	if (req->sg_cnt > BIO_MAX_PAGES)
>  		return -EINVAL;
>  
> -	if (req->transfer_len <= NVMET_MAX_INLINE_DATA_LEN) {
> -		bio = &req->p.inline_bio;
> -		bio_init(bio, req->inline_bvec, ARRAY_SIZE(req->inline_bvec));
> -	} else {
> -		bio = bio_alloc(GFP_KERNEL, min(req->sg_cnt, BIO_MAX_PAGES));
> -		bio->bi_end_io = bio_put;
> -	}
> +	bio = nvmet_req_bio_get(req, bio_put);
>  	bio->bi_opf = req_op(rq);
>  
>  	for_each_sg(req->sg, sg, req->sg_cnt, i) {
> diff --git a/drivers/nvme/target/zns.c b/drivers/nvme/target/zns.c
> index 2a71f56e568d..c32e93a3c7e1 100644
> --- a/drivers/nvme/target/zns.c
> +++ b/drivers/nvme/target/zns.c
> @@ -296,13 +296,7 @@ void nvmet_bdev_execute_zone_append(struct nvmet_req *req)
>  		return;
>  	}
>  
> -	if (req->transfer_len <= NVMET_MAX_INLINE_DATA_LEN) {
> -		bio = &req->b.inline_bio;
> -		bio_init(bio, req->inline_bvec, ARRAY_SIZE(req->inline_bvec));
> -	} else {
> -		bio = bio_alloc(GFP_KERNEL, req->sg_cnt);
> -	}
> -
> +	bio = nvmet_req_bio_get(req, NULL);
>  	bio_set_dev(bio, req->ns->bdev);
>  	bio->bi_iter.bi_sector = sect;
>  	bio->bi_opf = REQ_OP_ZONE_APPEND | REQ_SYNC | REQ_IDLE;
> 
-- 
Damien Le Moal
Western Digital Research


From Damien.LeMoal at wdc.com  Tue Jan 12 00:40:13 2021
From: Damien.LeMoal at wdc.com (Damien Le Moal)
Date: Tue, 12 Jan 2021 05:40:13 +0000
Subject: [PATCH V9 6/9] nvmet: add bio init helper for different backends
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-7-chaitanya.kulkarni@wdc.com>
Message-ID: <BL0PR04MB6514DF0B740BE6F4AB3141AEE7AA0@BL0PR04MB6514.namprd04.prod.outlook.com>

On 2021/01/12 13:27, Chaitanya Kulkarni wrote:
> With the addition of the zns backend now we have two different backends
> with the same bio initialization code. That leads to having duplicate
> code in two backends: generic bdev and generic zns.
> 
> Add a helper function to reduce the duplicate code such that helper
> function initializes the various bio initialization parameters such as
> bio block device, op flags, sector, end io callback, and private member,
> 
> Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
> ---
>  drivers/nvme/target/io-cmd-bdev.c |  6 +-----
>  drivers/nvme/target/nvmet.h       | 11 +++++++++++
>  drivers/nvme/target/zns.c         |  6 +++---
>  3 files changed, 15 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
> index 72746e29cb0d..b1fb0bb1f39f 100644
> --- a/drivers/nvme/target/io-cmd-bdev.c
> +++ b/drivers/nvme/target/io-cmd-bdev.c
> @@ -267,11 +267,7 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req)
>  	sector = nvmet_lba_to_sect(req->ns, req->cmd->rw.slba);
>  
>  	bio = nvmet_req_bio_get(req, NULL);
> -	bio_set_dev(bio, req->ns->bdev);
> -	bio->bi_iter.bi_sector = sector;
> -	bio->bi_private = req;
> -	bio->bi_end_io = nvmet_bio_done;
> -	bio->bi_opf = op;
> +	nvmet_bio_init(bio, req->ns->bdev, op, sector, req, nvmet_bio_done);
>  
>  	blk_start_plug(&plug);
>  	if (req->metadata_len)
> diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
> index 3fc84f79cce1..1ec9e1b35c67 100644
> --- a/drivers/nvme/target/nvmet.h
> +++ b/drivers/nvme/target/nvmet.h
> @@ -668,4 +668,15 @@ static inline struct bio *nvmet_req_bio_get(struct nvmet_req *req,
>  	return bio;
>  }
>  
> +static inline void nvmet_bio_init(struct bio *bio, struct block_device *bdev,
> +				  unsigned int op, sector_t sect, void *private,
> +				  bio_end_io_t *bi_end_io)
> +{
> +	bio_set_dev(bio, bdev);
> +	bio->bi_opf = op;
> +	bio->bi_iter.bi_sector = sect;
> +	bio->bi_private = private;
> +	bio->bi_end_io = bi_end_io;
> +}
> +
>  #endif /* _NVMET_H */
> diff --git a/drivers/nvme/target/zns.c b/drivers/nvme/target/zns.c
> index c32e93a3c7e1..92213bed0006 100644
> --- a/drivers/nvme/target/zns.c
> +++ b/drivers/nvme/target/zns.c
> @@ -281,6 +281,7 @@ void nvmet_bdev_execute_zone_append(struct nvmet_req *req)
>  {
>  	sector_t sect = nvmet_lba_to_sect(req->ns, req->cmd->rw.slba);
>  	struct request_queue *q = req->ns->bdev->bd_disk->queue;
> +	unsigned int op = REQ_OP_ZONE_APPEND | REQ_SYNC | REQ_IDLE;
>  	unsigned int max_sects = queue_max_zone_append_sectors(q);
>  	u16 status = NVME_SC_SUCCESS;
>  	unsigned int total_len = 0;
> @@ -297,9 +298,8 @@ void nvmet_bdev_execute_zone_append(struct nvmet_req *req)
>  	}
>  
>  	bio = nvmet_req_bio_get(req, NULL);
> -	bio_set_dev(bio, req->ns->bdev);
> -	bio->bi_iter.bi_sector = sect;
> -	bio->bi_opf = REQ_OP_ZONE_APPEND | REQ_SYNC | REQ_IDLE;
> +	nvmet_bio_init(bio, req->ns->bdev, op, sect, NULL, NULL);

op is used only here I think. So is that variable really necessary ?

> +
>  	if (req->cmd->rw.control & cpu_to_le16(NVME_RW_FUA))
>  		bio->bi_opf |= REQ_FUA;
>  
> 

Apart from the nit above, looks good to me.

Reviewed-by: Damien Le Moal <damien.lemoal at wdc.com>

-- 
Damien Le Moal
Western Digital Research


From Damien.LeMoal at wdc.com  Tue Jan 12 00:40:21 2021
From: Damien.LeMoal at wdc.com (Damien Le Moal)
Date: Tue, 12 Jan 2021 05:40:21 +0000
Subject: [PATCH V9 1/9] block: export bio_add_hw_pages()
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-2-chaitanya.kulkarni@wdc.com>
Message-ID: <BL0PR04MB6514D012AC158AB3F873C387E7AA0@BL0PR04MB6514.namprd04.prod.outlook.com>

On 2021/01/12 13:26, Chaitanya Kulkarni wrote:
> To implement the NVMe Zone Append command on the NVMeOF target side for
> generic Zoned Block Devices with NVMe Zoned Namespaces interface, we
> need to build the bios with hardware limitations, i.e. we use
> bio_add_hw_page() with queue_max_zone_append_sectors() instead of
> bio_add_page().
> 
> Without this API being exported NVMeOF target will require to use
> bio_add_hw_page() caller bio_iov_iter_get_pages(). That results in
> extra work which is inefficient.
> 
> Export the API so that NVMeOF ZBD over ZNS backend can use it to build
> Zone Append bios.
> 
> Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
> ---
>  block/bio.c            | 1 +
>  block/blk.h            | 4 ----
>  include/linux/blkdev.h | 4 ++++
>  3 files changed, 5 insertions(+), 4 deletions(-)
> 
> diff --git a/block/bio.c b/block/bio.c
> index 1f2cc1fbe283..5cbd56b54f98 100644
> --- a/block/bio.c
> +++ b/block/bio.c
> @@ -826,6 +826,7 @@ int bio_add_hw_page(struct request_queue *q, struct bio *bio,
>  	bio->bi_iter.bi_size += len;
>  	return len;
>  }
> +EXPORT_SYMBOL(bio_add_hw_page);
>  
>  /**
>   * bio_add_pc_page	- attempt to add page to passthrough bio
> diff --git a/block/blk.h b/block/blk.h
> index 7550364c326c..200030b2d74f 100644
> --- a/block/blk.h
> +++ b/block/blk.h
> @@ -351,8 +351,4 @@ int bdev_resize_partition(struct block_device *bdev, int partno,
>  		sector_t start, sector_t length);
>  int disk_expand_part_tbl(struct gendisk *disk, int target);
>  
> -int bio_add_hw_page(struct request_queue *q, struct bio *bio,
> -		struct page *page, unsigned int len, unsigned int offset,
> -		unsigned int max_sectors, bool *same_page);
> -
>  #endif /* BLK_INTERNAL_H */
> diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
> index 070de09425ad..028ccc9bdf8d 100644
> --- a/include/linux/blkdev.h
> +++ b/include/linux/blkdev.h
> @@ -2005,6 +2005,10 @@ struct block_device *I_BDEV(struct inode *inode);
>  struct block_device *bdgrab(struct block_device *bdev);
>  void bdput(struct block_device *);
>  
> +int bio_add_hw_page(struct request_queue *q, struct bio *bio,
> +		struct page *page, unsigned int len, unsigned int offset,
> +		unsigned int max_sectors, bool *same_page);
> +
>  #ifdef CONFIG_BLOCK
>  void invalidate_bdev(struct block_device *bdev);
>  int truncate_bdev_range(struct block_device *bdev, fmode_t mode, loff_t lstart,
> 

Looks good.

Reviewed-by: Damien Le Moal <damien.lemoal at wdc.com>

-- 
Damien Le Moal
Western Digital Research


From Chaitanya.Kulkarni at wdc.com  Tue Jan 12 00:55:29 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Tue, 12 Jan 2021 05:55:29 +0000
Subject: [PATCH V9 5/9] nvmet: add bio get helper for different backends
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-6-chaitanya.kulkarni@wdc.com>
 <BL0PR04MB651444A9A810E0DA8D958431E7AA0@BL0PR04MB6514.namprd04.prod.outlook.com>
Message-ID: <BYAPR04MB49656232D23482CAE1948FAE86AA0@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/11/21 21:37, Damien Le Moal wrote:
>> diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
>> index 7361665585a2..3fc84f79cce1 100644
>> --- a/drivers/nvme/target/nvmet.h
>> +++ b/drivers/nvme/target/nvmet.h
>> @@ -652,4 +652,20 @@ nvmet_bdev_execute_zone_append(struct nvmet_req *req)
>>  }
>>  #endif /* CONFIG_BLK_DEV_ZONED */
>>  
>> +static inline struct bio *nvmet_req_bio_get(struct nvmet_req *req,
>> +					    bio_end_io_t *bi_end_io)
>> +{
>> +	struct bio *bio;
>> +
>> +	if (req->transfer_len <= NVMET_MAX_INLINE_DATA_LEN) {
>> +		bio = &req->b.inline_bio;
>> +		bio_init(bio, req->inline_bvec, ARRAY_SIZE(req->inline_bvec));
>> +		return bio;
>> +	}
>> +
>> +	bio = bio_alloc(GFP_KERNEL, req->sg_cnt);
> I have a doubt about the use of GFP_KERNEL here... Shouldn't these be GFP_NOIO ?
> The code was like this so it is may be OK, but without GFP_NOIO, is forward
> progress guaranteed ? No recursion possible ?
>
I've kept the original behavior, let check if this needs to be
GFP_KERNEL or not,
if so I'll send a separate patch with a proper message.

Thanks for pointing this out.


From Chaitanya.Kulkarni at wdc.com  Tue Jan 12 00:57:38 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Tue, 12 Jan 2021 05:57:38 +0000
Subject: [PATCH V9 6/9] nvmet: add bio init helper for different backends
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-7-chaitanya.kulkarni@wdc.com>
 <BL0PR04MB6514DF0B740BE6F4AB3141AEE7AA0@BL0PR04MB6514.namprd04.prod.outlook.com>
Message-ID: <BYAPR04MB496575ACE95FA2E6EA31AC8286AA0@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/11/21 21:40, Damien Le Moal wrote:
>>  	bio = nvmet_req_bio_get(req, NULL);
>> -	bio_set_dev(bio, req->ns->bdev);
>> -	bio->bi_iter.bi_sector = sect;
>> -	bio->bi_opf = REQ_OP_ZONE_APPEND | REQ_SYNC | REQ_IDLE;
>> +	nvmet_bio_init(bio, req->ns->bdev, op, sect, NULL, NULL);
> op is used only here I think. So is that variable really necessary ?
>
This is just my personal preference as without using op we will have to
add a new line to a function call, I like to keep the function call in
one line as much as I can.


From Chaitanya.Kulkarni at wdc.com  Tue Jan 12 01:11:02 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Tue, 12 Jan 2021 06:11:02 +0000
Subject: [PATCH V9 4/9] nvmet: add ZBD over ZNS backend support
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-5-chaitanya.kulkarni@wdc.com>
 <BL0PR04MB6514A4C7F0F7A2627C4639B3E7AA0@BL0PR04MB6514.namprd04.prod.outlook.com>
Message-ID: <BYAPR04MB4965A589B5D8F480355AC28986AA0@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/11/21 21:32, Damien Le Moal wrote:
> On 2021/01/12 13:27, Chaitanya Kulkarni wrote:
>> NVMe TP 4053 ? Zoned Namespaces (ZNS) allows host software to
>> communicate with a non-volatile memory subsystem using zones for
>> NVMe protocol based controllers. NVMeOF already support the ZNS NVMe
>> Protocol compliant devices on the target in the passthru mode. There
>> are Generic zoned block devices like  Shingled Magnetic Recording (SMR)
>> HDDs that are not based on the NVMe protocol.
>>
>> This patch adds ZNS backend to support the ZBDs for NVMeOF target.
>>
>> This support includes implementing the new command set NVME_CSI_ZNS,
>> adding different command handlers for ZNS command set such as
>> NVMe Identify Controller, NVMe Identify Namespace, NVMe Zone Append,
>> NVMe Zone Management Send and NVMe Zone Management Receive.
>>
>> With new command set identifier we also update the target command effects
>> logs to reflect the ZNS compliant commands.
>>
>> Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
>> ---
>>  drivers/nvme/target/Makefile      |   1 +
>>  drivers/nvme/target/admin-cmd.c   |  28 +++
>>  drivers/nvme/target/core.c        |   3 +
>>  drivers/nvme/target/io-cmd-bdev.c |  33 ++-
>>  drivers/nvme/target/nvmet.h       |  38 ++++
>>  drivers/nvme/target/zns.c         | 342 ++++++++++++++++++++++++++++++
>>  6 files changed, 437 insertions(+), 8 deletions(-)
>>  create mode 100644 drivers/nvme/target/zns.c
>>
>> diff --git a/drivers/nvme/target/Makefile b/drivers/nvme/target/Makefile
>> index ebf91fc4c72e..9837e580fa7e 100644
>> --- a/drivers/nvme/target/Makefile
>> +++ b/drivers/nvme/target/Makefile
>> @@ -12,6 +12,7 @@ obj-$(CONFIG_NVME_TARGET_TCP)		+= nvmet-tcp.o
>>  nvmet-y		+= core.o configfs.o admin-cmd.o fabrics-cmd.o \
>>  			discovery.o io-cmd-file.o io-cmd-bdev.o
>>  nvmet-$(CONFIG_NVME_TARGET_PASSTHRU)	+= passthru.o
>> +nvmet-$(CONFIG_BLK_DEV_ZONED)		+= zns.o
>>  nvme-loop-y	+= loop.o
>>  nvmet-rdma-y	+= rdma.o
>>  nvmet-fc-y	+= fc.o
>> diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
>> index a50b7bcac67a..bdf09d8faa48 100644
>> --- a/drivers/nvme/target/admin-cmd.c
>> +++ b/drivers/nvme/target/admin-cmd.c
>> @@ -191,6 +191,15 @@ static void nvmet_execute_get_log_cmd_effects_ns(struct nvmet_req *req)
>>  		log->iocs[nvme_cmd_dsm]			= cpu_to_le32(1 << 0);
>>  		log->iocs[nvme_cmd_write_zeroes]	= cpu_to_le32(1 << 0);
>>  		break;
>> +	case NVME_CSI_ZNS:
>> +		if (IS_ENABLED(CONFIG_BLK_DEV_ZONED)) {
>> +			u32 *iocs = log->iocs;
>> +
>> +			iocs[nvme_cmd_zone_append]	= cpu_to_le32(1 << 0);
>> +			iocs[nvme_cmd_zone_mgmt_send]	= cpu_to_le32(1 << 0);
>> +			iocs[nvme_cmd_zone_mgmt_recv]	= cpu_to_le32(1 << 0);
>> +		}
> Is it OK to not return an error here if CONFIG_BLK_DEV_ZONED is not enabled ?
> I have not checked the entire code of this function nor how it is called, so I
> may be wrong.
Since we only set the controller cap when CONFIG_BLK_DEV_ZONED is
enabled we should be uniform everywhere in the code, I'll recheck
and make the change if needed.
>> +		break;
>>  	default:
>>  		status = NVME_SC_INVALID_LOG_PAGE;
>>  		break;
>> @@ -644,6 +653,17 @@ static void nvmet_execute_identify_desclist(struct nvmet_req *req)
>>  	if (status)
>>  		goto out;
>>  
>> +	if (IS_ENABLED(CONFIG_BLK_DEV_ZONED)) {
>> +		u16 nvme_cis_zns = NVME_CSI_ZNS;
>> +
>> +		if (req->ns->csi == NVME_CSI_ZNS)
>> +			status = nvmet_copy_ns_identifier(req, NVME_NIDT_CSI,
>> +							  NVME_NIDT_CSI_LEN,
>> +							  &nvme_cis_zns, &off);
>> +		if (status)
>> +			goto out;
>> +	}
> Same comment here.
I think same explanation applies here too, will recheck and make the change
if needed.
>
>> +
>>  	if (sg_zero_buffer(req->sg, req->sg_cnt, NVME_IDENTIFY_DATA_SIZE - off,
>>  			off) != NVME_IDENTIFY_DATA_SIZE - off)
>>  		status = NVME_SC_INTERNAL | NVME_SC_DNR;
>> @@ -660,8 +680,16 @@ static void nvmet_execute_identify(struct nvmet_req *req)
>>  	switch (req->cmd->identify.cns) {
>>  	case NVME_ID_CNS_NS:
>>  		return nvmet_execute_identify_ns(req);
>> +	case NVME_ID_CNS_CS_NS:
>> +		if (req->cmd->identify.csi == NVME_CSI_ZNS)
>> +			return nvmet_execute_identify_cns_cs_ns(req);
>> +		break;
>>  	case NVME_ID_CNS_CTRL:
>>  		return nvmet_execute_identify_ctrl(req);
>> +	case NVME_ID_CNS_CS_CTRL:
>> +		if (req->cmd->identify.csi == NVME_CSI_ZNS)
>> +			return nvmet_execute_identify_cns_cs_ctrl(req);
>> +		break;
>>  	case NVME_ID_CNS_NS_ACTIVE_LIST:
>>  		return nvmet_execute_identify_nslist(req);
>>  	case NVME_ID_CNS_NS_DESC_LIST:
>> diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
>> index 672e4009f8d6..17d5da062a5a 100644
>> --- a/drivers/nvme/target/core.c
>> +++ b/drivers/nvme/target/core.c
>> @@ -1107,6 +1107,7 @@ static inline u8 nvmet_cc_iocqes(u32 cc)
>>  static inline bool nvmet_cc_css_check(u8 cc_css)
>>  {
>>  	switch (cc_css <<= NVME_CC_CSS_SHIFT) {
>> +	case NVME_CC_CSS_CSI:
>>  	case NVME_CC_CSS_NVM:
>>  		return true;
>>  	default:
>> @@ -1173,6 +1174,8 @@ static void nvmet_init_cap(struct nvmet_ctrl *ctrl)
>>  {
>>  	/* command sets supported: NVMe command set: */
>>  	ctrl->cap = (1ULL << 37);
>> +	if (IS_ENABLED(CONFIG_BLK_DEV_ZONED))
>> +		ctrl->cap |= (1ULL << 43);
>>  	/* CC.EN timeout in 500msec units: */
>>  	ctrl->cap |= (15ULL << 24);
>>  	/* maximum queue entries supported: */
>> diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
>> index 23095bdfce06..6178ef643962 100644
>> --- a/drivers/nvme/target/io-cmd-bdev.c
>> +++ b/drivers/nvme/target/io-cmd-bdev.c
>> @@ -63,6 +63,14 @@ static void nvmet_bdev_ns_enable_integrity(struct nvmet_ns *ns)
>>  	}
>>  }
>>  
>> +void nvmet_bdev_ns_disable(struct nvmet_ns *ns)
>> +{
>> +	if (ns->bdev) {
>> +		blkdev_put(ns->bdev, FMODE_WRITE | FMODE_READ);
>> +		ns->bdev = NULL;
>> +	}
>> +}
>> +
>>  int nvmet_bdev_ns_enable(struct nvmet_ns *ns)
>>  {
>>  	int ret;
>> @@ -86,15 +94,15 @@ int nvmet_bdev_ns_enable(struct nvmet_ns *ns)
>>  	if (IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY_T10))
>>  		nvmet_bdev_ns_enable_integrity(ns);
>>  
>> -	return 0;
>> -}
>> -
>> -void nvmet_bdev_ns_disable(struct nvmet_ns *ns)
>> -{
>> -	if (ns->bdev) {
>> -		blkdev_put(ns->bdev, FMODE_WRITE | FMODE_READ);
>> -		ns->bdev = NULL;
>> +	if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) && bdev_is_zoned(ns->bdev)) {
>> +		if (!nvmet_bdev_zns_enable(ns)) {
>> +			nvmet_bdev_ns_disable(ns);
>> +			return -EINVAL;
>> +		}
>> +		ns->csi = NVME_CSI_ZNS;
>>  	}
>> +
>> +	return 0;
>>  }
>>  
>>  void nvmet_bdev_ns_revalidate(struct nvmet_ns *ns)
>> @@ -448,6 +456,15 @@ u16 nvmet_bdev_parse_io_cmd(struct nvmet_req *req)
>>  	case nvme_cmd_write_zeroes:
>>  		req->execute = nvmet_bdev_execute_write_zeroes;
>>  		return 0;
>> +	case nvme_cmd_zone_append:
>> +		req->execute = nvmet_bdev_execute_zone_append;
>> +		return 0;
>> +	case nvme_cmd_zone_mgmt_recv:
>> +		req->execute = nvmet_bdev_execute_zone_mgmt_recv;
>> +		return 0;
>> +	case nvme_cmd_zone_mgmt_send:
>> +		req->execute = nvmet_bdev_execute_zone_mgmt_send;
>> +		return 0;
>>  	default:
>>  		pr_err("unhandled cmd %d on qid %d\n", cmd->common.opcode,
>>  		       req->sq->qid);
>> diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
>> index 476b3cd91c65..7361665585a2 100644
>> --- a/drivers/nvme/target/nvmet.h
>> +++ b/drivers/nvme/target/nvmet.h
>> @@ -252,6 +252,10 @@ struct nvmet_subsys {
>>  	unsigned int		admin_timeout;
>>  	unsigned int		io_timeout;
>>  #endif /* CONFIG_NVME_TARGET_PASSTHRU */
>> +
>> +#ifdef CONFIG_BLK_DEV_ZONED
>> +	u8			zasl;
>> +#endif /* CONFIG_BLK_DEV_ZONED */
>>  };
>>  
>>  static inline struct nvmet_subsys *to_subsys(struct config_item *item)
>> @@ -614,4 +618,38 @@ static inline sector_t nvmet_lba_to_sect(struct nvmet_ns *ns, __le64 lba)
>>  	return le64_to_cpu(lba) << (ns->blksize_shift - SECTOR_SHIFT);
>>  }
>>  
>> +#ifdef CONFIG_BLK_DEV_ZONED
>> +bool nvmet_bdev_zns_enable(struct nvmet_ns *ns);
>> +void nvmet_execute_identify_cns_cs_ctrl(struct nvmet_req *req);
>> +void nvmet_execute_identify_cns_cs_ns(struct nvmet_req *req);
>> +void nvmet_bdev_execute_zone_mgmt_recv(struct nvmet_req *req);
>> +void nvmet_bdev_execute_zone_mgmt_send(struct nvmet_req *req);
>> +void nvmet_bdev_execute_zone_append(struct nvmet_req *req);
>> +#else  /* CONFIG_BLK_DEV_ZONED */
>> +static inline bool nvmet_bdev_zns_enable(struct nvmet_ns *ns)
>> +{
>> +	return false;
>> +}
>> +static inline void
>> +nvmet_execute_identify_cns_cs_ctrl(struct nvmet_req *req)
>> +{
>> +}
>> +static inline void
>> +nvmet_execute_identify_cns_cs_ns(struct nvmet_req *req)
>> +{
>> +}
>> +static inline void
>> +nvmet_bdev_execute_zone_mgmt_recv(struct nvmet_req *req)
>> +{
>> +}
>> +static inline void
>> +nvmet_bdev_execute_zone_mgmt_send(struct nvmet_req *req)
>> +{
>> +}
>> +static inline void
>> +nvmet_bdev_execute_zone_append(struct nvmet_req *req)
>> +{
>> +}
>> +#endif /* CONFIG_BLK_DEV_ZONED */
>> +
>>  #endif /* _NVMET_H */
>> diff --git a/drivers/nvme/target/zns.c b/drivers/nvme/target/zns.c
>> new file mode 100644
>> index 000000000000..2a71f56e568d
>> --- /dev/null
>> +++ b/drivers/nvme/target/zns.c
>> @@ -0,0 +1,342 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * NVMe ZNS-ZBD command implementation.
>> + * Copyright (c) 2020-2021 HGST, a Western Digital Company.
>> + */
>> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>> +#include <linux/nvme.h>
>> +#include <linux/blkdev.h>
>> +#include "nvmet.h"
>> +
>> +/*
>> + * We set the Memory Page Size Minimum (MPSMIN) for target controller to 0
>> + * which gets added by 12 in the nvme_enable_ctrl() which results in 2^12 = 4k
>> + * as page_shift value. When calculating the ZASL use shift by 12.
>> + */
>> +#define NVMET_MPSMIN_SHIFT	12
>> +
>> +static u16 nvmet_bdev_zns_checks(struct nvmet_req *req)
>> +{
>> +	u16 status = NVME_SC_SUCCESS;
>> +
>> +	if (!bdev_is_zoned(req->ns->bdev)) {
>> +		status = NVME_SC_INVALID_NS | NVME_SC_DNR;
>> +		goto out;
>> +	}
>> +
>> +	if (req->cmd->zmr.zra != NVME_ZRA_ZONE_REPORT) {
>> +		status = NVME_SC_INVALID_FIELD;
>> +		goto out;
>> +	}
>> +
>> +	if (req->cmd->zmr.zrasf != NVME_ZRASF_ZONE_REPORT_ALL) {
>> +		status = NVME_SC_INVALID_FIELD;
>> +		goto out;
>> +	}
>> +
>> +	if (req->cmd->zmr.pr != NVME_REPORT_ZONE_PARTIAL)
>> +		status = NVME_SC_INVALID_FIELD;
>> +
>> +out:
> You really want to keep this (useless) label ? Without it, the status variable
> can be dropped and the code overall becomes so much easier to read... Not to
> mention that life will be easier to the compiler for optimizing this.
>
Will remove it in the next version.
>> +	return status;
>> +}
>> +
>> +/*
>> + *  ZNS related command implementation and helpers.
>> + */
>> +
>> +static inline u8 nvmet_zasl(unsigned int zone_append_sects)
>> +{
>> +	/*
>> +	 * Zone Append Size Limit is the value experessed in the units
>> +	 * of minimum memory page size (i.e. 12) and is reported power of 2.
>> +	 */
>> +	return ilog2((zone_append_sects << 9) >> NVMET_MPSMIN_SHIFT);
>> +}
>> +
>> +static inline bool nvmet_zns_update_zasl(struct nvmet_ns *ns)
>> +{
>> +	struct request_queue *q = ns->bdev->bd_disk->queue;
>> +	u8 zasl = nvmet_zasl(queue_max_zone_append_sectors(q));
>> +
>> +	if (ns->subsys->zasl)
>> +		return ns->subsys->zasl < zasl ? false : true;
>> +
>> +	ns->subsys->zasl = zasl;
>> +	return true;
>> +}
>> +
>> +
>> +static int nvmet_bdev_validate_zns_zones_cb(struct blk_zone *z,
>> +					    unsigned int idx, void *data)
>> +{
>> +	if (z->type == BLK_ZONE_TYPE_CONVENTIONAL)
>> +		return -EOPNOTSUPP;
>> +	return 0;
>> +}
>> +
>> +static bool nvmet_bdev_has_conv_zones(struct block_device *bdev)
>> +{
>> +	int ret;
>> +
>> +	if (bdev->bd_disk->queue->conv_zones_bitmap)
>> +		return true;
>> +
>> +	ret = blkdev_report_zones(bdev, 0, blkdev_nr_zones(bdev->bd_disk),
>> +				  nvmet_bdev_validate_zns_zones_cb, NULL);
>> +
>> +	return ret < 0 ? true : false;
> return ret <= 0;
>
> would be simpler.
>
> Note that "<=" includes the error case of the device not reporting any zone
> (device dead) as we should fail that case I think.
>
hmm will make that change.
>> +}
>> +
>> +bool nvmet_bdev_zns_enable(struct nvmet_ns *ns)
>> +{
>> +	if (nvmet_bdev_has_conv_zones(ns->bdev))
>> +		return false;
>> +
>> +	/*
>> +	 * For ZBC and ZAC devices, writes into sequential zones must be aligned
>> +	 * to the device physical block size. So use this value as the logical
>> +	 * block size to avoid errors.
>> +	 */
>> +	ns->blksize_shift = blksize_bits(bdev_physical_block_size(ns->bdev));
>> +
>> +	if (!nvmet_zns_update_zasl(ns))
>> +		return false;
>> +
>> +	return !(get_capacity(ns->bdev->bd_disk) &
>> +			(bdev_zone_sectors(ns->bdev) - 1));
>> +}
>> +
>> +/*
>> + * ZNS related Admin and I/O command handlers.
>> + */
>> +void nvmet_execute_identify_cns_cs_ctrl(struct nvmet_req *req)
>> +{
>> +	u8 zasl = req->sq->ctrl->subsys->zasl;
>> +	struct nvmet_ctrl *ctrl = req->sq->ctrl;
>> +	struct nvme_id_ctrl_zns *id;
>> +	u16 status;
>> +
>> +	id = kzalloc(sizeof(*id), GFP_KERNEL);
>> +	if (!id) {
>> +		status = NVME_SC_INTERNAL;
>> +		goto out;
>> +	}
>> +
>> +	if (ctrl->ops->get_mdts)
>> +		id->zasl = min_t(u8, ctrl->ops->get_mdts(ctrl), zasl);
>> +	else
>> +		id->zasl = zasl;
>> +
>> +	status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id));
>> +
>> +	kfree(id);
>> +out:
>> +	nvmet_req_complete(req, status);
>> +}
>> +
>> +void nvmet_execute_identify_cns_cs_ns(struct nvmet_req *req)
>> +{
>> +	struct nvme_id_ns_zns *id_zns;
>> +	u16 status = NVME_SC_SUCCESS;
>> +	u64 zsze;
>> +
>> +	if (le32_to_cpu(req->cmd->identify.nsid) == NVME_NSID_ALL) {
>> +		req->error_loc = offsetof(struct nvme_identify, nsid);
>> +		status = NVME_SC_INVALID_NS | NVME_SC_DNR;
>> +		goto out;
>> +	}
>> +
>> +	id_zns = kzalloc(sizeof(*id_zns), GFP_KERNEL);
>> +	if (!id_zns) {
>> +		status = NVME_SC_INTERNAL;
>> +		goto out;
>> +	}
>> +
>> +	req->ns = nvmet_find_namespace(req->sq->ctrl, req->cmd->identify.nsid);
>> +	if (!req->ns) {
>> +		status = NVME_SC_INTERNAL;
>> +		goto done;
>> +	}
>> +
>> +	if (!bdev_is_zoned(req->ns->bdev)) {
>> +		req->error_loc = offsetof(struct nvme_identify, nsid);
>> +		status = NVME_SC_INVALID_NS | NVME_SC_DNR;
>> +		goto done;
>> +	}
>> +
>> +	nvmet_ns_revalidate(req->ns);
>> +	zsze = (bdev_zone_sectors(req->ns->bdev) << 9) >>
>> +					req->ns->blksize_shift;
>> +	id_zns->lbafe[0].zsze = cpu_to_le64(zsze);
>> +	id_zns->mor = cpu_to_le32(bdev_max_open_zones(req->ns->bdev));
>> +	id_zns->mar = cpu_to_le32(bdev_max_active_zones(req->ns->bdev));
>> +
>> +done:
>> +	status = nvmet_copy_to_sgl(req, 0, id_zns, sizeof(*id_zns));
>> +	kfree(id_zns);
>> +out:
>> +	nvmet_req_complete(req, status);
>> +}
>> +
>> +struct nvmet_report_zone_data {
>> +	struct nvmet_ns *ns;
>> +	struct nvme_zone_report *rz;
>> +};
>> +
>> +static int nvmet_bdev_report_zone_cb(struct blk_zone *z, unsigned int idx,
>> +				     void *data)
>> +{
>> +	struct nvmet_report_zone_data *report_zone_data = data;
>> +	struct nvme_zone_descriptor *entries = report_zone_data->rz->entries;
>> +	struct nvmet_ns *ns = report_zone_data->ns;
>> +
>> +	entries[idx].zcap = nvmet_sect_to_lba(ns, z->capacity);
>> +	entries[idx].zslba = nvmet_sect_to_lba(ns, z->start);
>> +	entries[idx].wp = nvmet_sect_to_lba(ns, z->wp);
>> +	entries[idx].za = z->reset ? 1 << 2 : 0;
>> +	entries[idx].zt = z->type;
>> +	entries[idx].zs = z->cond << 4;
>> +
>> +	return 0;
>> +}
>> +
>> +void nvmet_bdev_execute_zone_mgmt_recv(struct nvmet_req *req)
>> +{
>> +	sector_t sect = nvmet_lba_to_sect(req->ns, req->cmd->zmr.slba);
>> +	u32 bufsize = (le32_to_cpu(req->cmd->zmr.numd) + 1) << 2;
>> +	struct nvmet_report_zone_data data = { .ns = req->ns };
>> +	unsigned int nr_zones;
>> +	int reported_zones;
>> +	u16 status;
>> +
>> +	nr_zones = (bufsize - sizeof(struct nvme_zone_report)) /
>> +			sizeof(struct nvme_zone_descriptor);
> I really would prefer this code to be moved down, before the call to
> blkdev_report_zones().
>
> You can also optimize this value a little with a min() of the value above and of
> DIV_ROUND_UP(dev_capacity - sect, zone size). But not a big deal I think.
I did that as per your last comment, when I did the code review with
host side it didn't match, I've a cleanup patch series to fix nits and
host side css checks for zns I've added this into that series.
>> +
>> +	status = nvmet_bdev_zns_checks(req);
>> +	if (status)
>> +		goto out;
>> +
>> +	data.rz = __vmalloc(bufsize, GFP_KERNEL | __GFP_NORETRY | __GFP_ZERO);
> Shouldn't this be GFP_NOIO ? Also, is the NORETRY critical ?
Yes on GFP_NOIO. NORETRY critical means how we areallocating the memory on
the host side nvme_zns_alloc_report_buffer() ?
> blkdev_report_zones() will do mem allocation too and at leadt scsi does retry.
>
>> +	if (!data.rz) {
>> +		status = NVME_SC_INTERNAL;
>> +		goto out;
>> +	}
>> +
>> +	reported_zones = blkdev_report_zones(req->ns->bdev, sect, nr_zones,
>> +					     nvmet_bdev_report_zone_cb,
>> +					     &data);
>> +	if (reported_zones < 0) {
>> +		status = NVME_SC_INTERNAL;
>> +		goto out_free_report_zones;
>> +	}
>> +
>> +	data.rz->nr_zones = cpu_to_le64(reported_zones);
>> +
>> +	status = nvmet_copy_to_sgl(req, 0, data.rz, bufsize);
>> +
>> +out_free_report_zones:
>> +	kvfree(data.rz);
>> +out:
>> +	nvmet_req_complete(req, status);
>> +}
>> +
>> +void nvmet_bdev_execute_zone_mgmt_send(struct nvmet_req *req)
>> +{
>> +	sector_t sect = nvmet_lba_to_sect(req->ns, req->cmd->zms.slba);
>> +	sector_t nr_sect = bdev_zone_sectors(req->ns->bdev);
>> +	u16 status = NVME_SC_SUCCESS;
>> +	enum req_opf op;
>> +	int ret;
>> +
>> +	if (req->cmd->zms.select_all)
>> +		nr_sect = get_capacity(req->ns->bdev->bd_disk);
>> +
>> +	switch (req->cmd->zms.zsa) {
>> +	case NVME_ZONE_OPEN:
>> +		op = REQ_OP_ZONE_OPEN;
>> +		break;
>> +	case NVME_ZONE_CLOSE:
>> +		op = REQ_OP_ZONE_CLOSE;
>> +		break;
>> +	case NVME_ZONE_FINISH:
>> +		op = REQ_OP_ZONE_FINISH;
>> +		break;
>> +	case NVME_ZONE_RESET:
>> +		op = REQ_OP_ZONE_RESET;
>> +		break;
>> +	default:
>> +		status = NVME_SC_INVALID_FIELD;
>> +		goto out;
>> +	}
>> +
>> +	ret = blkdev_zone_mgmt(req->ns->bdev, op, sect, nr_sect, GFP_KERNEL);
> GFP_NOIO ?
Yes.
>
>> +	if (ret)
>> +		status = NVME_SC_INTERNAL;
>> +out:
>> +	nvmet_req_complete(req, status);
>> +}
>> +
>> +void nvmet_bdev_execute_zone_append(struct nvmet_req *req)
>> +{
>> +	sector_t sect = nvmet_lba_to_sect(req->ns, req->cmd->rw.slba);
>> +	struct request_queue *q = req->ns->bdev->bd_disk->queue;
>> +	unsigned int max_sects = queue_max_zone_append_sectors(q);
>> +	u16 status = NVME_SC_SUCCESS;
>> +	unsigned int total_len = 0;
>> +	struct scatterlist *sg;
>> +	int ret = 0, sg_cnt;
>> +	struct bio *bio;
>> +
>> +	if (!nvmet_check_transfer_len(req, nvmet_rw_data_len(req)))
>> +		return;
>> +
>> +	if (!req->sg_cnt) {
>> +		nvmet_req_complete(req, 0);
>> +		return;
>> +	}
>> +
>> +	if (req->transfer_len <= NVMET_MAX_INLINE_DATA_LEN) {
>> +		bio = &req->b.inline_bio;
>> +		bio_init(bio, req->inline_bvec, ARRAY_SIZE(req->inline_bvec));
>> +	} else {
>> +		bio = bio_alloc(GFP_KERNEL, req->sg_cnt);
>> +	}
>> +
>> +	bio_set_dev(bio, req->ns->bdev);
>> +	bio->bi_iter.bi_sector = sect;
>> +	bio->bi_opf = REQ_OP_ZONE_APPEND | REQ_SYNC | REQ_IDLE;
>> +	if (req->cmd->rw.control & cpu_to_le16(NVME_RW_FUA))
>> +		bio->bi_opf |= REQ_FUA;
>> +
>> +	for_each_sg(req->sg, sg, req->sg_cnt, sg_cnt) {
>> +		struct page *p = sg_page(sg);
>> +		unsigned int l = sg->length;
>> +		unsigned int o = sg->offset;
>> +		bool same_page = false;
>> +
>> +		ret = bio_add_hw_page(q, bio, p, l, o, max_sects, &same_page);
>> +		if (ret != sg->length) {
>> +			status = NVME_SC_INTERNAL;
>> +			goto out_bio_put;
>> +		}
>> +		if (same_page)
>> +			put_page(p);
>> +
>> +		total_len += sg->length;
>> +	}
>> +
>> +	if (total_len != nvmet_rw_data_len(req)) {
>> +		status = NVME_SC_INTERNAL | NVME_SC_DNR;
>> +		goto out_bio_put;
>> +	}
>> +
>> +	ret = submit_bio_wait(bio);
>> +	req->cqe->result.u64 = nvmet_sect_to_lba(req->ns,
>> +						 bio->bi_iter.bi_sector);
>> +
>> +out_bio_put:
>> +	if (bio != &req->b.inline_bio)
>> +		bio_put(bio);
>> +	nvmet_req_complete(req, ret < 0 ? NVME_SC_INTERNAL : status);
>> +}
>>
>



From Chaitanya.Kulkarni at wdc.com  Tue Jan 12 01:12:58 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Tue, 12 Jan 2021 06:12:58 +0000
Subject: [PATCH V9 0/9] nvmet: add ZBD backend support
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
Message-ID: <BYAPR04MB4965A5ABC937908A0D88C0AA86AA0@BYAPR04MB4965.namprd04.prod.outlook.com>

Damien,

On 1/11/21 20:26, Chaitanya Kulkarni wrote:
> Hi,
>
> NVMeOF Host is capable of handling the NVMe Protocol based Zoned Block
> Devices (ZBD) in the Zoned Namespaces (ZNS) mode with the passthru
> backend. There is no support for a generic block device backend to
> handle the ZBD devices which are not NVMe protocol compliant.
>
> This adds support to export the ZBDs (which are not NVMe drives) to host
> the from target via NVMeOF using the host side ZNS interface.
>
> The patch series is generated in bottom-top manner where, it first adds
> prep patch and ZNS command-specific handlers on the top of genblk and 
> updates the data structures, then one by one it wires up the admin cmds
> in the order host calls them in namespace initializing sequence. Once
> everything is ready, it wires-up the I/O command handlers. See below for
> patch-series overview.
>
> All the testcases are passing for the ZoneFS where ZBD exported with
> NVMeOF backed by null_blk ZBD and null_blk ZBD without NVMeOF. Adding
> test result below.
>
> Note: This patch-series is based on the earlier posted patch series :-
>
> [PATCH V2 0/4] nvmet: admin-cmd related cleanups and a fix
> http://lists.infradead.org/pipermail/linux-nvme/2021-January/021729.html
>
> -ck

thanks a lot or your comments, I'll send a V10 with fixes for your comments.


From Damien.LeMoal at wdc.com  Tue Jan 12 01:27:22 2021
From: Damien.LeMoal at wdc.com (Damien Le Moal)
Date: Tue, 12 Jan 2021 06:27:22 +0000
Subject: [PATCH V9 6/9] nvmet: add bio init helper for different backends
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-7-chaitanya.kulkarni@wdc.com>
 <BL0PR04MB6514DF0B740BE6F4AB3141AEE7AA0@BL0PR04MB6514.namprd04.prod.outlook.com>
 <BYAPR04MB496575ACE95FA2E6EA31AC8286AA0@BYAPR04MB4965.namprd04.prod.outlook.com>
Message-ID: <BL0PR04MB651407876C76BDFBB5029D5DE7AA0@BL0PR04MB6514.namprd04.prod.outlook.com>

On 2021/01/12 14:57, Chaitanya Kulkarni wrote:
> On 1/11/21 21:40, Damien Le Moal wrote:
>>>  	bio = nvmet_req_bio_get(req, NULL);
>>> -	bio_set_dev(bio, req->ns->bdev);
>>> -	bio->bi_iter.bi_sector = sect;
>>> -	bio->bi_opf = REQ_OP_ZONE_APPEND | REQ_SYNC | REQ_IDLE;
>>> +	nvmet_bio_init(bio, req->ns->bdev, op, sect, NULL, NULL);
>> op is used only here I think. So is that variable really necessary ?
>>
> This is just my personal preference as without using op we will have to
> add a new line to a function call, I like to keep the function call in
> one line as much as I can.

A new line in the code costs nothing. An unnecessary variable costs stack space...


-- 
Damien Le Moal
Western Digital Research


From Damien.LeMoal at wdc.com  Tue Jan 12 01:31:33 2021
From: Damien.LeMoal at wdc.com (Damien Le Moal)
Date: Tue, 12 Jan 2021 06:31:33 +0000
Subject: [PATCH V9 4/9] nvmet: add ZBD over ZNS backend support
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-5-chaitanya.kulkarni@wdc.com>
 <BL0PR04MB6514A4C7F0F7A2627C4639B3E7AA0@BL0PR04MB6514.namprd04.prod.outlook.com>
 <BYAPR04MB4965A589B5D8F480355AC28986AA0@BYAPR04MB4965.namprd04.prod.outlook.com>
Message-ID: <BL0PR04MB65145A8886218E4C56C6122FE7AA0@BL0PR04MB6514.namprd04.prod.outlook.com>

On 2021/01/12 15:11, Chaitanya Kulkarni wrote:
[...]
>>> +void nvmet_bdev_execute_zone_mgmt_recv(struct nvmet_req *req)
>>> +{
>>> +	sector_t sect = nvmet_lba_to_sect(req->ns, req->cmd->zmr.slba);
>>> +	u32 bufsize = (le32_to_cpu(req->cmd->zmr.numd) + 1) << 2;
>>> +	struct nvmet_report_zone_data data = { .ns = req->ns };
>>> +	unsigned int nr_zones;
>>> +	int reported_zones;
>>> +	u16 status;
>>> +
>>> +	nr_zones = (bufsize - sizeof(struct nvme_zone_report)) /
>>> +			sizeof(struct nvme_zone_descriptor);
>> I really would prefer this code to be moved down, before the call to
>> blkdev_report_zones().
>>
>> You can also optimize this value a little with a min() of the value above and of
>> DIV_ROUND_UP(dev_capacity - sect, zone size). But not a big deal I think.
> I did that as per your last comment, when I did the code review with
> host side it didn't match, I've a cleanup patch series to fix nits and
> host side css checks for zns I've added this into that series.
>>> +
>>> +	status = nvmet_bdev_zns_checks(req);
>>> +	if (status)
>>> +		goto out;
>>> +
>>> +	data.rz = __vmalloc(bufsize, GFP_KERNEL | __GFP_NORETRY | __GFP_ZERO);
>> Shouldn't this be GFP_NOIO ? Also, is the NORETRY critical ?
> Yes on GFP_NOIO. NORETRY critical means how we areallocating the memory on
> the host side nvme_zns_alloc_report_buffer() ?

By critical, I mean that if __GFP_NORETRY is removed, things break ? Or is it
just an optimization to avoid overtaxing the host resources ? I suspect the
latter case, but wanted to make sure.



-- 
Damien Le Moal
Western Digital Research


From sagi at grimberg.me  Tue Jan 12 01:49:07 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Mon, 11 Jan 2021 22:49:07 -0800
Subject: Data corruption when using multiple devices with NVMEoF TCP
In-Reply-To: <CACVXFVNwhFTq2Aq7bx7cwmhab4itkAntF-TKunv59XoZySy51w@mail.gmail.com>
References: <CAJS6EdjsTVgs3JK3q2DePjEz1A0s9RJTOwqo=Ka7kinNMECtJw@mail.gmail.com>
 <20201223084332.GA30502@infradead.org>
 <CAJS6EdijX6ws_wHxygdpcYGtB6JFwLDbDE3A0t0QUYS-LbRakg@mail.gmail.com>
 <16d876c1-524a-38d3-3cff-99ec694464b2@grimberg.me>
 <CAJS6EdivEF0c=3FmKj4wGZoVRKbUvjH_qJLXmO7Tvwsp+km0rw@mail.gmail.com>
 <f631893c-5ce9-95fd-c32c-35a7e70d093c@grimberg.me>
 <CAJS6EdjUAb77-rWd=XmFhsM2_3Hds6VV6jQUVPJoJQHhk12J_Q@mail.gmail.com>
 <a6564a08-a3b0-5c22-51e3-712c4714bcc5@grimberg.me>
 <CAJS6Edgb+yCW5q5dA=MEkL0eYs4MXoopdiz72nhkxpkd5Fe_cA@mail.gmail.com>
 <ae5b1654-e580-88be-0498-0cd111b53fa2@grimberg.me>
 <CAJS6Edjkfvs4pfH9XvwAT0h4STuoDh1PahSxkkTWOsKwgL5pZQ@mail.gmail.com>
 <16fe1e9c-3a43-ef28-7b69-755e6a86464f@grimberg.me>
 <CAJS6Edi9Es1zR9QC+=kwVjAFAGYrEru4vibW42ffyWoMDutFhQ@mail.gmail.com>
 <4684c86a-8cc7-c5ae-0d6b-9f0e7c59eda5@grimberg.me>
 <fcb56817-1f34-e307-e888-45ebb661c31d@grimberg.me>
 <CACVXFVNwhFTq2Aq7bx7cwmhab4itkAntF-TKunv59XoZySy51w@mail.gmail.com>
Message-ID: <bd3d4c8f-459e-1fa0-2a98-3bdb3e83de4a@grimberg.me>


>>> Hey Hao,
>>>
>>>> Here is the entire log (and it's a new one, i.e. above snippet not
>>>> included):
>>>> https://drive.google.com/file/d/16ArIs5-Jw4P2f17A_ftKLm1A4LQUFpmg/view?usp=sharing
>>>>
>>>>
>>>> What I found is the data corruption does not always happen, especially
>>>> when I copy a small directory. So I guess a lot of log entries should
>>>> just look fine.
>>>
>>> So this seems to be a breakage that existed for some time now with
>>> multipage bvecs that you have been the first one to report. This
>>> seems to be related to bio merges, which is seems strange to me
>>> why this just now comes up, perhaps it is the combination with
>>> raid0 that triggers this, I'm not sure.
>>
>> OK, I think I understand what is going on. With multipage bvecs
>> bios can split in the middle of a bvec entry, and then merge
>> back with another bio.
> 
> IMO, bio split can be done in the middle of a bvec even though the bvec
> is single page. The split may just be triggered in case of raid over nvme-tcp,
> and I guess it might be triggered by device mapper too.

Yes, but I couldn't find a case where it cannot happen, but it only
triggered with mdraid. I'll wait for Hao to verify and send a formal
patch.


From hch at lst.de  Tue Jan 12 02:24:41 2021
From: hch at lst.de (Christoph Hellwig)
Date: Tue, 12 Jan 2021 08:24:41 +0100
Subject: [PATCH V9 1/9] block: export bio_add_hw_pages()
In-Reply-To: <20210112042623.6316-2-chaitanya.kulkarni@wdc.com>
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-2-chaitanya.kulkarni@wdc.com>
Message-ID: <20210112072441.GA24155@lst.de>

EXPORT_SYMBOL_GPL, please.


From hch at lst.de  Tue Jan 12 02:27:15 2021
From: hch at lst.de (Christoph Hellwig)
Date: Tue, 12 Jan 2021 08:27:15 +0100
Subject: [PATCH V9 3/9] nvmet: add NVM command set identifier support
In-Reply-To: <20210112042623.6316-4-chaitanya.kulkarni@wdc.com>
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-4-chaitanya.kulkarni@wdc.com>
Message-ID: <20210112072715.GB24155@lst.de>

The Command Set Identifier has no "NVM" in its name.


> +static inline bool nvmet_cc_css_check(u8 cc_css)
> +{
> +	switch (cc_css <<= NVME_CC_CSS_SHIFT) {
> +	case NVME_CC_CSS_NVM:
> +		return true;
> +	default:
> +		return false;
> +	}
> +}

This hunk looks misplaced, it isn't very useful on its own, but
should go together with the multiple command set support.


From hch at lst.de  Tue Jan 12 02:30:03 2021
From: hch at lst.de (Christoph Hellwig)
Date: Tue, 12 Jan 2021 08:30:03 +0100
Subject: [PATCH V2 4/4] nvmet: set right status on error in id-ns handler
In-Reply-To: <20210104045203.24472-5-chaitanya.kulkarni@wdc.com>
References: <20210104045203.24472-1-chaitanya.kulkarni@wdc.com>
 <20210104045203.24472-5-chaitanya.kulkarni@wdc.com>
Message-ID: <20210112073003.GA24211@lst.de>

Can you reorder this patch so that it applies as a straight fix without
the cleanups?


From hch at lst.de  Tue Jan 12 02:33:15 2021
From: hch at lst.de (Christoph Hellwig)
Date: Tue, 12 Jan 2021 08:33:15 +0100
Subject: [PATCH V9 5/9] nvmet: add bio get helper for different backends
In-Reply-To: <20210112042623.6316-6-chaitanya.kulkarni@wdc.com>
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-6-chaitanya.kulkarni@wdc.com>
Message-ID: <20210112073315.GA24288@lst.de>

I'm not a huge fan of this helper, especially as it sets an end_io
callback only for the allocated case, which is a weird calling
convention.


From hch at lst.de  Tue Jan 12 02:33:58 2021
From: hch at lst.de (Christoph Hellwig)
Date: Tue, 12 Jan 2021 08:33:58 +0100
Subject: [PATCH V9 6/9] nvmet: add bio init helper for different backends
In-Reply-To: <20210112042623.6316-7-chaitanya.kulkarni@wdc.com>
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-7-chaitanya.kulkarni@wdc.com>
Message-ID: <20210112073358.GB24288@lst.de>

> +static inline void nvmet_bio_init(struct bio *bio, struct block_device *bdev,
> +				  unsigned int op, sector_t sect, void *private,
> +				  bio_end_io_t *bi_end_io)
> +{
> +	bio_set_dev(bio, bdev);
> +	bio->bi_opf = op;
> +	bio->bi_iter.bi_sector = sect;
> +	bio->bi_private = private;
> +	bio->bi_end_io = bi_end_io;
> +}

Nothing NVMe specific about this.  The helper also doesn't relaly contain
any logic either.


From hch at lst.de  Tue Jan 12 02:35:03 2021
From: hch at lst.de (Christoph Hellwig)
Date: Tue, 12 Jan 2021 08:35:03 +0100
Subject: [PATCH V9 8/9] nvmet: add common I/O length check helper
In-Reply-To: <20210112042623.6316-9-chaitanya.kulkarni@wdc.com>
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-9-chaitanya.kulkarni@wdc.com>
Message-ID: <20210112073503.GC24288@lst.de>

I can't say I like this helper.  The semantics are a little confusing,
not helped by the name.


From hch at lst.de  Tue Jan 12 02:36:06 2021
From: hch at lst.de (Christoph Hellwig)
Date: Tue, 12 Jan 2021 08:36:06 +0100
Subject: [PATCH V9 9/9] nvmet: call nvmet_bio_done() for zone append
In-Reply-To: <20210112042623.6316-10-chaitanya.kulkarni@wdc.com>
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-10-chaitanya.kulkarni@wdc.com>
Message-ID: <20210112073606.GD24288@lst.de>

I don't see much of a need to share such trivial functionality over
different codebases.


From hch at lst.de  Tue Jan 12 02:48:05 2021
From: hch at lst.de (Christoph Hellwig)
Date: Tue, 12 Jan 2021 08:48:05 +0100
Subject: [PATCH V9 4/9] nvmet: add ZBD over ZNS backend support
In-Reply-To: <20210112042623.6316-5-chaitanya.kulkarni@wdc.com>
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-5-chaitanya.kulkarni@wdc.com>
Message-ID: <20210112074805.GA24443@lst.de>

> diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
> index a50b7bcac67a..bdf09d8faa48 100644
> --- a/drivers/nvme/target/admin-cmd.c
> +++ b/drivers/nvme/target/admin-cmd.c
> @@ -191,6 +191,15 @@ static void nvmet_execute_get_log_cmd_effects_ns(struct nvmet_req *req)
>  		log->iocs[nvme_cmd_dsm]			= cpu_to_le32(1 << 0);
>  		log->iocs[nvme_cmd_write_zeroes]	= cpu_to_le32(1 << 0);
>  		break;
> +	case NVME_CSI_ZNS:
> +		if (IS_ENABLED(CONFIG_BLK_DEV_ZONED)) {
> +			u32 *iocs = log->iocs;
> +
> +			iocs[nvme_cmd_zone_append]	= cpu_to_le32(1 << 0);
> +			iocs[nvme_cmd_zone_mgmt_send]	= cpu_to_le32(1 << 0);
> +			iocs[nvme_cmd_zone_mgmt_recv]	= cpu_to_le32(1 << 0);
> +		}
> +		break;

We need to return errors if the command set is not actually supported.
I also think splitting this into one helper per command set would
be nice.

> @@ -644,6 +653,17 @@ static void nvmet_execute_identify_desclist(struct nvmet_req *req)
>  	if (status)
>  		goto out;
>  
> +	if (IS_ENABLED(CONFIG_BLK_DEV_ZONED)) {
> +		u16 nvme_cis_zns = NVME_CSI_ZNS;
> +
> +		if (req->ns->csi == NVME_CSI_ZNS)
> +			status = nvmet_copy_ns_identifier(req, NVME_NIDT_CSI,
> +							  NVME_NIDT_CSI_LEN,
> +							  &nvme_cis_zns, &off);
> +		if (status)
> +			goto out;
> +	}

We need to add the CSI for every namespace, i.e. something like:

	status = nvmet_copy_ns_identifier(req, NVME_NIDT_CSI, NVME_NIDT_CSI_LEN,
					  &req->ns->csi);		
	if (status)
		goto out;

and this hunk needs to go into the CSI patch.

>  	if (sg_zero_buffer(req->sg, req->sg_cnt, NVME_IDENTIFY_DATA_SIZE - off,
>  			off) != NVME_IDENTIFY_DATA_SIZE - off)
>  		status = NVME_SC_INTERNAL | NVME_SC_DNR;
> @@ -660,8 +680,16 @@ static void nvmet_execute_identify(struct nvmet_req *req)
>  	switch (req->cmd->identify.cns) {
>  	case NVME_ID_CNS_NS:
>  		return nvmet_execute_identify_ns(req);
> +	case NVME_ID_CNS_CS_NS:
> +		if (req->cmd->identify.csi == NVME_CSI_ZNS)
> +			return nvmet_execute_identify_cns_cs_ns(req);
> +		break;
>  	case NVME_ID_CNS_CTRL:
>  		return nvmet_execute_identify_ctrl(req);
> +	case NVME_ID_CNS_CS_CTRL:
> +		if (req->cmd->identify.csi == NVME_CSI_ZNS)
> +			return nvmet_execute_identify_cns_cs_ctrl(req);
> +		break;

How does the CSI get mirrored into the cns field?

> diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
> index 672e4009f8d6..17d5da062a5a 100644
> --- a/drivers/nvme/target/core.c
> +++ b/drivers/nvme/target/core.c
> @@ -1107,6 +1107,7 @@ static inline u8 nvmet_cc_iocqes(u32 cc)
>  static inline bool nvmet_cc_css_check(u8 cc_css)
>  {
>  	switch (cc_css <<= NVME_CC_CSS_SHIFT) {
> +	case NVME_CC_CSS_CSI:
>  	case NVME_CC_CSS_NVM:
>  		return true;
>  	default:
> @@ -1173,6 +1174,8 @@ static void nvmet_init_cap(struct nvmet_ctrl *ctrl)
>  {
>  	/* command sets supported: NVMe command set: */
>  	ctrl->cap = (1ULL << 37);
> +	if (IS_ENABLED(CONFIG_BLK_DEV_ZONED))
> +		ctrl->cap |= (1ULL << 43);
>  	/* CC.EN timeout in 500msec units: */
>  	ctrl->cap |= (15ULL << 24);
>  	/* maximum queue entries supported: */

This needs to go into a separate patch for multiple command set support.
We can probably merge the CAP and CC bits with the CSI support, though.

> +	if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) && bdev_is_zoned(ns->bdev)) {

bdev_is_zoned should be probably stubbed out for !CONFIG_BLK_DEV_ZONED
these days.

> +/*
> + *  ZNS related command implementation and helpers.
> + */

Well, that is the description of the whole file, isn't it?  I don't think
this comment adds much value.

> +	/*
> +	 * For ZBC and ZAC devices, writes into sequential zones must be aligned
> +	 * to the device physical block size. So use this value as the logical
> +	 * block size to avoid errors.
> +	 */

I do not understand the logic here, given that NVMe does not have
conventional zones.


From Damien.LeMoal at wdc.com  Tue Jan 12 02:52:27 2021
From: Damien.LeMoal at wdc.com (Damien Le Moal)
Date: Tue, 12 Jan 2021 07:52:27 +0000
Subject: [PATCH V9 4/9] nvmet: add ZBD over ZNS backend support
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-5-chaitanya.kulkarni@wdc.com>
 <20210112074805.GA24443@lst.de>
Message-ID: <BL0PR04MB65145CE93F2AAF66158A3D71E7AA0@BL0PR04MB6514.namprd04.prod.outlook.com>

On 2021/01/12 16:48, Christoph Hellwig wrote:
>> diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
>> index a50b7bcac67a..bdf09d8faa48 100644
>> --- a/drivers/nvme/target/admin-cmd.c
>> +++ b/drivers/nvme/target/admin-cmd.c
>> @@ -191,6 +191,15 @@ static void nvmet_execute_get_log_cmd_effects_ns(struct nvmet_req *req)
>>  		log->iocs[nvme_cmd_dsm]			= cpu_to_le32(1 << 0);
>>  		log->iocs[nvme_cmd_write_zeroes]	= cpu_to_le32(1 << 0);
>>  		break;
>> +	case NVME_CSI_ZNS:
>> +		if (IS_ENABLED(CONFIG_BLK_DEV_ZONED)) {
>> +			u32 *iocs = log->iocs;
>> +
>> +			iocs[nvme_cmd_zone_append]	= cpu_to_le32(1 << 0);
>> +			iocs[nvme_cmd_zone_mgmt_send]	= cpu_to_le32(1 << 0);
>> +			iocs[nvme_cmd_zone_mgmt_recv]	= cpu_to_le32(1 << 0);
>> +		}
>> +		break;
> 
> We need to return errors if the command set is not actually supported.
> I also think splitting this into one helper per command set would
> be nice.
> 
>> @@ -644,6 +653,17 @@ static void nvmet_execute_identify_desclist(struct nvmet_req *req)
>>  	if (status)
>>  		goto out;
>>  
>> +	if (IS_ENABLED(CONFIG_BLK_DEV_ZONED)) {
>> +		u16 nvme_cis_zns = NVME_CSI_ZNS;
>> +
>> +		if (req->ns->csi == NVME_CSI_ZNS)
>> +			status = nvmet_copy_ns_identifier(req, NVME_NIDT_CSI,
>> +							  NVME_NIDT_CSI_LEN,
>> +							  &nvme_cis_zns, &off);
>> +		if (status)
>> +			goto out;
>> +	}
> 
> We need to add the CSI for every namespace, i.e. something like:
> 
> 	status = nvmet_copy_ns_identifier(req, NVME_NIDT_CSI, NVME_NIDT_CSI_LEN,
> 					  &req->ns->csi);		
> 	if (status)
> 		goto out;
> 
> and this hunk needs to go into the CSI patch.
> 
>>  	if (sg_zero_buffer(req->sg, req->sg_cnt, NVME_IDENTIFY_DATA_SIZE - off,
>>  			off) != NVME_IDENTIFY_DATA_SIZE - off)
>>  		status = NVME_SC_INTERNAL | NVME_SC_DNR;
>> @@ -660,8 +680,16 @@ static void nvmet_execute_identify(struct nvmet_req *req)
>>  	switch (req->cmd->identify.cns) {
>>  	case NVME_ID_CNS_NS:
>>  		return nvmet_execute_identify_ns(req);
>> +	case NVME_ID_CNS_CS_NS:
>> +		if (req->cmd->identify.csi == NVME_CSI_ZNS)
>> +			return nvmet_execute_identify_cns_cs_ns(req);
>> +		break;
>>  	case NVME_ID_CNS_CTRL:
>>  		return nvmet_execute_identify_ctrl(req);
>> +	case NVME_ID_CNS_CS_CTRL:
>> +		if (req->cmd->identify.csi == NVME_CSI_ZNS)
>> +			return nvmet_execute_identify_cns_cs_ctrl(req);
>> +		break;
> 
> How does the CSI get mirrored into the cns field?
> 
>> diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
>> index 672e4009f8d6..17d5da062a5a 100644
>> --- a/drivers/nvme/target/core.c
>> +++ b/drivers/nvme/target/core.c
>> @@ -1107,6 +1107,7 @@ static inline u8 nvmet_cc_iocqes(u32 cc)
>>  static inline bool nvmet_cc_css_check(u8 cc_css)
>>  {
>>  	switch (cc_css <<= NVME_CC_CSS_SHIFT) {
>> +	case NVME_CC_CSS_CSI:
>>  	case NVME_CC_CSS_NVM:
>>  		return true;
>>  	default:
>> @@ -1173,6 +1174,8 @@ static void nvmet_init_cap(struct nvmet_ctrl *ctrl)
>>  {
>>  	/* command sets supported: NVMe command set: */
>>  	ctrl->cap = (1ULL << 37);
>> +	if (IS_ENABLED(CONFIG_BLK_DEV_ZONED))
>> +		ctrl->cap |= (1ULL << 43);
>>  	/* CC.EN timeout in 500msec units: */
>>  	ctrl->cap |= (15ULL << 24);
>>  	/* maximum queue entries supported: */
> 
> This needs to go into a separate patch for multiple command set support.
> We can probably merge the CAP and CC bits with the CSI support, though.
> 
>> +	if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) && bdev_is_zoned(ns->bdev)) {
> 
> bdev_is_zoned should be probably stubbed out for !CONFIG_BLK_DEV_ZONED
> these days.
> 
>> +/*
>> + *  ZNS related command implementation and helpers.
>> + */
> 
> Well, that is the description of the whole file, isn't it?  I don't think
> this comment adds much value.
> 
>> +	/*
>> +	 * For ZBC and ZAC devices, writes into sequential zones must be aligned
>> +	 * to the device physical block size. So use this value as the logical
>> +	 * block size to avoid errors.
>> +	 */
> 
> I do not understand the logic here, given that NVMe does not have
> conventional zones.

512e SAS & SATA SMR drives (512B logical, 4K physical) are a big thing, and for
these, all writes in sequential zones must be 4K aligned. So I suggested to
Chaitanya to simply use the physical block size as the LBA size for the target
to avoid weird IO errors that would not make sense in ZNS/NVMe world (e.g. 512B
aligned write requests failing).


-- 
Damien Le Moal
Western Digital Research


From hch at lst.de  Tue Jan 12 03:06:00 2021
From: hch at lst.de (Christoph Hellwig)
Date: Tue, 12 Jan 2021 09:06:00 +0100
Subject: [PATCH 1/3] nvme: support command retry delay for admin command
In-Reply-To: <20210110013316.GA4369@localhost.localdomain>
References: <20210108144659.7126-1-minwoo.im.dev@gmail.com>
 <20210108144659.7126-2-minwoo.im.dev@gmail.com>
 <BYAPR04MB4965078A7B0C75B03D342EFD86AD0@BYAPR04MB4965.namprd04.prod.outlook.com>
 <20210110013316.GA4369@localhost.localdomain>
Message-ID: <20210112080600.GA24949@lst.de>

On Sun, Jan 10, 2021 at 10:33:16AM +0900, Minwoo Im wrote:
> Hello,
> 
> On 21-01-09 20:34:11, Chaitanya Kulkarni wrote:
> > On 1/8/21 06:54, Minwoo Im wrote:
> > > This feature can be applied not only I/O queue commands, but also admin
> > > queue commands.  Admin command during the initialization may fail due to
> > > some un-ready state of a controller, so it would be better to have this
> > > feature for admin commands also.
> > What is some un-ready state ?
> 
> State that controller is unable to process successfully command as
> "Command Interrupt" status code represents.

Given that controller ready has a specific meaning in NVMe I think a
different wording here would be useful.


From hch at lst.de  Tue Jan 12 03:06:53 2021
From: hch at lst.de (Christoph Hellwig)
Date: Tue, 12 Jan 2021 09:06:53 +0100
Subject: [PATCH 1/3] nvme: support command retry delay for admin command
In-Reply-To: <20210108144659.7126-2-minwoo.im.dev@gmail.com>
References: <20210108144659.7126-1-minwoo.im.dev@gmail.com>
 <20210108144659.7126-2-minwoo.im.dev@gmail.com>
Message-ID: <20210112080653.GB24949@lst.de>

Except for the little wording issue this looks good to me.  I'll pick it
up for nvme-5.11 and will fix up the commit log.


From hch at lst.de  Tue Jan 12 03:08:40 2021
From: hch at lst.de (Christoph Hellwig)
Date: Tue, 12 Jan 2021 09:08:40 +0100
Subject: [PATCH 2/3] nvme: check all retry delay times in Identify
 Controller
In-Reply-To: <20210108144659.7126-3-minwoo.im.dev@gmail.com>
References: <20210108144659.7126-1-minwoo.im.dev@gmail.com>
 <20210108144659.7126-3-minwoo.im.dev@gmail.com>
Message-ID: <20210112080840.GC24949@lst.de>

On Fri, Jan 08, 2021 at 11:46:58PM +0900, Minwoo Im wrote:
> If none of Command Retry Delay Time(CRDT)s are set, then we can simply
> skip to configure Advanced Command Retry Enable(ACRE).
> 
> CRDT selection will be made in Completion Queue Entry that controller
> has responsibility to decide.
> 
> This patch checks all CRDT[0, 1, and 2] in Identify Controller data
> structrure instead of checking the first one: CRDT[0].

Why?


From hch at lst.de  Tue Jan 12 03:09:26 2021
From: hch at lst.de (Christoph Hellwig)
Date: Tue, 12 Jan 2021 09:09:26 +0100
Subject: [PATCH 3/3] nvme: add parameter command_retry to enable retry
In-Reply-To: <20210108144659.7126-4-minwoo.im.dev@gmail.com>
References: <20210108144659.7126-1-minwoo.im.dev@gmail.com>
 <20210108144659.7126-4-minwoo.im.dev@gmail.com>
Message-ID: <20210112080926.GD24949@lst.de>

On Fri, Jan 08, 2021 at 11:46:59PM +0900, Minwoo Im wrote:
> This patch added a module parameter named command_retry to turn on the
> command retry feature in this driver.  If turning it on,
> REQ3_FAILFAST_DRIVER will not be set to requests so that retry can be
> reached out to nvme_retry_req() based on the module parameter.

Why would we want to do that, and if so why only conditional on a module
parameter?


From hch at lst.de  Tue Jan 12 03:26:41 2021
From: hch at lst.de (Christoph Hellwig)
Date: Tue, 12 Jan 2021 09:26:41 +0100
Subject: [PATCH v2] nvmet-fc: associations list protected by rcu,
 instead of spinlock_irq where possible.
In-Reply-To: <1609697575-103348-2-git-send-email-leonid.ravich@dell.com>
References: <20201224110542.22219-1-leonid.ravich@dell.com>
 <1609697575-103348-1-git-send-email-leonid.ravich@dell.com>
 <1609697575-103348-2-git-send-email-leonid.ravich@dell.com>
Message-ID: <20210112082641.GA25502@lst.de>

Thanks,

applied to nvme-5.11.


From hch at lst.de  Tue Jan 12 03:26:49 2021
From: hch at lst.de (Christoph Hellwig)
Date: Tue, 12 Jan 2021 09:26:49 +0100
Subject: [PATCH 1/2] nvmet: Use nvmet_is_port_enabled helper for pi_enable
In-Reply-To: <1610033654-25186-1-git-send-email-israelr@nvidia.com>
References: <1610033654-25186-1-git-send-email-israelr@nvidia.com>
Message-ID: <20210112082649.GB25502@lst.de>

Thanks,

applied to nvme-5.11.


From hch at lst.de  Tue Jan 12 03:27:01 2021
From: hch at lst.de (Christoph Hellwig)
Date: Tue, 12 Jan 2021 09:27:01 +0100
Subject: [PATCH] nvme: Constify static attribute_group structs
In-Reply-To: <20210108234147.42151-1-rikard.falkeborn@gmail.com>
References: <20210108234147.42151-1-rikard.falkeborn@gmail.com>
Message-ID: <20210112082701.GC25502@lst.de>

Thanks,

applied to nvme-5.11.


From hch at lst.de  Tue Jan 12 03:27:08 2021
From: hch at lst.de (Christoph Hellwig)
Date: Tue, 12 Jan 2021 09:27:08 +0100
Subject: [PATCH] nvmet-rdma: Fix NULL deref when setting pi_enable and
 traddr INADDR_ANY
In-Reply-To: <1610280545-57812-1-git-send-email-israelr@nvidia.com>
References: <1610280545-57812-1-git-send-email-israelr@nvidia.com>
Message-ID: <20210112082708.GD25502@lst.de>

Thanks,

applied to nvme-5.11.


From hch at lst.de  Tue Jan 12 03:33:00 2021
From: hch at lst.de (Christoph Hellwig)
Date: Tue, 12 Jan 2021 09:33:00 +0100
Subject: [PATCH] nvme: trace: parse format nvm command in detail
In-Reply-To: <20210111201552.GA90320@michal-desk>
References: <20210104155343.GA26034@michal-desk>
 <20210104160220.GB1024941@dhcp-10-100-145-180.wdc.com>
 <20210106090053.GA32643@lst.de>
 <20210108223431.GA1451691@dhcp-10-100-145-180.wdc.com>
 <CAPcyv4jLWOKDTyGzwar4C0H5euggvD_Ak6NESLd9=1THGC=ASg@mail.gmail.com>
 <20210111170110.GC1458209@dhcp-10-100-145-180.wdc.com>
 <CAPcyv4g3LKRmUOj1QHmkQ5rZ4BfH6TQaK6jKhXfb2DoBW-MoUQ@mail.gmail.com>
 <20210111175018.GD1458209@dhcp-10-100-145-180.wdc.com>
 <20210111201552.GA90320@michal-desk>
Message-ID: <20210112083300.GA25601@lst.de>

On Mon, Jan 11, 2021 at 09:15:52PM +0100, Michal Krakowiak wrote:
> Like Dan, I really appreciate having the trace parsed in the kernel. I 
> understand the concerns. What about having both: detailed parsing and raw 
> bytes? It does not seem to me like a big deal to append a field with the 
> raw data even if detailed parsing is implemented. Let the parsing extends 
> the raw data instead of replacing them. This will result in the detailed 
> human-friendly output (which is nice to have) while not losing data in the 
> future (in the case that a new unsupported by parser field appears).

That is how the kernel trace events work, including for the block layer.
blktrace is a separate piece of software that attaches to the raw
tracepoints and adds its own handling, so I don't think it is the right
comparism here.


From minwoo.im.dev at gmail.com  Tue Jan 12 03:40:37 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Tue, 12 Jan 2021 17:40:37 +0900
Subject: [PATCH 2/3] nvme: check all retry delay times in Identify
 Controller
In-Reply-To: <20210112080840.GC24949@lst.de>
References: <20210108144659.7126-1-minwoo.im.dev@gmail.com>
 <20210108144659.7126-3-minwoo.im.dev@gmail.com>
 <20210112080840.GC24949@lst.de>
Message-ID: <20210112084037.GA3227@localhost.localdomain>

Hello,

On 21-01-12 09:08:40, Christoph Hellwig wrote:
> On Fri, Jan 08, 2021 at 11:46:58PM +0900, Minwoo Im wrote:
> > If none of Command Retry Delay Time(CRDT)s are set, then we can simply
> > skip to configure Advanced Command Retry Enable(ACRE).
> > 
> > CRDT selection will be made in Completion Queue Entry that controller
> > has responsibility to decide.
> > 
> > This patch checks all CRDT[0, 1, and 2] in Identify Controller data
> > structrure instead of checking the first one: CRDT[0].
> 
> Why?

I thought we should check whether there's at least one CRDT fields are
set or not regardless to CRDT number (0, 1, and 2).  If CRDT[0] is not
set, but CRDT[1] is set, then we can go ahead with CRDT[1] not [0].

Thanks!


From minwoo.im.dev at gmail.com  Tue Jan 12 03:44:59 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Tue, 12 Jan 2021 17:44:59 +0900
Subject: [PATCH 3/3] nvme: add parameter command_retry to enable retry
In-Reply-To: <20210112080926.GD24949@lst.de>
References: <20210108144659.7126-1-minwoo.im.dev@gmail.com>
 <20210108144659.7126-4-minwoo.im.dev@gmail.com>
 <20210112080926.GD24949@lst.de>
Message-ID: <20210112084459.GB3227@localhost.localdomain>

Hello,

On 21-01-12 09:09:26, Christoph Hellwig wrote:
> On Fri, Jan 08, 2021 at 11:46:59PM +0900, Minwoo Im wrote:
> > This patch added a module parameter named command_retry to turn on the
> > command retry feature in this driver.  If turning it on,
> > REQ3_FAILFAST_DRIVER will not be set to requests so that retry can be
> > reached out to nvme_retry_req() based on the module parameter.
> 
> Why would we want to do that, and if so why only conditional on a module
> parameter?

If reqeust->cmd_flags are set with the REQ_FAILFAST_DRIVER in
nvme_init_request(), then it will always go to COMPLETE case rather than
RETRY in nvme_decide_disposition():

	if (blk_noretry_request(req) ||
		...

And I thought that to make command delay feature enabled, module
parameter was a good start to toggle this feature.

Thanks!


From minwoo.im.dev at gmail.com  Tue Jan 12 03:47:27 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Tue, 12 Jan 2021 17:47:27 +0900
Subject: [PATCH 1/3] nvme: support command retry delay for admin command
In-Reply-To: <20210112080653.GB24949@lst.de>
References: <20210108144659.7126-1-minwoo.im.dev@gmail.com>
 <20210108144659.7126-2-minwoo.im.dev@gmail.com>
 <20210112080653.GB24949@lst.de>
Message-ID: <20210112084727.GC3227@localhost.localdomain>

Hello,

On 21-01-12 09:06:53, Christoph Hellwig wrote:
> Except for the little wording issue this looks good to me.  I'll pick it
> up for nvme-5.11 and will fix up the commit log.

Thanks for the fix!


From pkuwangh at gmail.com  Tue Jan 12 03:55:59 2021
From: pkuwangh at gmail.com (Hao Wang)
Date: Tue, 12 Jan 2021 00:55:59 -0800
Subject: Data corruption when using multiple devices with NVMEoF TCP
In-Reply-To: <fcb56817-1f34-e307-e888-45ebb661c31d@grimberg.me>
References: <CAJS6EdjsTVgs3JK3q2DePjEz1A0s9RJTOwqo=Ka7kinNMECtJw@mail.gmail.com>
 <CAJS6Edh8aVAHhKRGqU+7v5C3KY7YxczVg_7Q8QrPGtyvVw7K3w@mail.gmail.com>
 <fd4541e4-78c5-ec3b-b272-467fd11f7472@grimberg.me>
 <20201223084332.GA30502@infradead.org>
 <CAJS6EdijX6ws_wHxygdpcYGtB6JFwLDbDE3A0t0QUYS-LbRakg@mail.gmail.com>
 <16d876c1-524a-38d3-3cff-99ec694464b2@grimberg.me>
 <CAJS6EdivEF0c=3FmKj4wGZoVRKbUvjH_qJLXmO7Tvwsp+km0rw@mail.gmail.com>
 <f631893c-5ce9-95fd-c32c-35a7e70d093c@grimberg.me>
 <CAJS6EdjUAb77-rWd=XmFhsM2_3Hds6VV6jQUVPJoJQHhk12J_Q@mail.gmail.com>
 <a6564a08-a3b0-5c22-51e3-712c4714bcc5@grimberg.me>
 <CAJS6Edgb+yCW5q5dA=MEkL0eYs4MXoopdiz72nhkxpkd5Fe_cA@mail.gmail.com>
 <ae5b1654-e580-88be-0498-0cd111b53fa2@grimberg.me>
 <CAJS6Edjkfvs4pfH9XvwAT0h4STuoDh1PahSxkkTWOsKwgL5pZQ@mail.gmail.com>
 <16fe1e9c-3a43-ef28-7b69-755e6a86464f@grimberg.me>
 <CAJS6Edi9Es1zR9QC+=kwVjAFAGYrEru4vibW42ffyWoMDutFhQ@mail.gmail.com>
 <4684c86a-8cc7-c5ae-0d6b-9f0e7c59eda5@grimberg.me>
 <fcb56817-1f34-e307-e888-45ebb661c31d@grimberg.me>
Message-ID: <CAJS6EdhW3d46zjXh7TVjFaB_Z4_=kA_fWcaEJKQdtLph56Y+kg@mail.gmail.com>

Yes, this patch fixes the problem! Thanks!

Tested on top of a0d54b4f5b21.

Hao

On Mon, Jan 11, 2021 at 5:29 PM Sagi Grimberg <sagi at grimberg.me> wrote:
>
>
> > Hey Hao,
> >
> >> Here is the entire log (and it's a new one, i.e. above snippet not
> >> included):
> >> https://drive.google.com/file/d/16ArIs5-Jw4P2f17A_ftKLm1A4LQUFpmg/view?usp=sharing
> >>
> >>
> >> What I found is the data corruption does not always happen, especially
> >> when I copy a small directory. So I guess a lot of log entries should
> >> just look fine.
> >
> > So this seems to be a breakage that existed for some time now with
> > multipage bvecs that you have been the first one to report. This
> > seems to be related to bio merges, which is seems strange to me
> > why this just now comes up, perhaps it is the combination with
> > raid0 that triggers this, I'm not sure.
>
> OK, I think I understand what is going on. With multipage bvecs
> bios can split in the middle of a bvec entry, and then merge
> back with another bio.
>
> The issue is that we are not capping the last bvec entry send length
> calculation in that.
>
> I think that just this can also resolve the issue:
> --
> diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
> index 973d5d683180..c6b0a189a494 100644
> --- a/drivers/nvme/host/tcp.c
> +++ b/drivers/nvme/host/tcp.c
> @@ -201,8 +201,9 @@ static inline size_t nvme_tcp_req_cur_offset(struct
> nvme_tcp_request *req)
>
>   static inline size_t nvme_tcp_req_cur_length(struct nvme_tcp_request *req)
>   {
> -       return min_t(size_t, req->iter.bvec->bv_len - req->iter.iov_offset,
> -                       req->pdu_len - req->pdu_sent);
> +       return min_t(size_t, req->iter.count,
> +                       min_t(size_t, req->iter.bvec->bv_len -
> req->iter.iov_offset,
> +                               req->pdu_len - req->pdu_sent));
>   }
>
>   static inline size_t nvme_tcp_pdu_data_left(struct nvme_tcp_request *req)
> --


From Chaitanya.Kulkarni at wdc.com  Tue Jan 12 04:02:53 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Tue, 12 Jan 2021 09:02:53 +0000
Subject: [PATCH V2 4/4] nvmet: set right status on error in id-ns handler
References: <20210104045203.24472-1-chaitanya.kulkarni@wdc.com>
 <20210104045203.24472-5-chaitanya.kulkarni@wdc.com>
 <20210112073003.GA24211@lst.de>
Message-ID: <BYAPR04MB4965C9A4E18F0C1968DC9D4286AA0@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/11/21 11:30 PM, Christoph Hellwig wrote:
> Can you reorder this patch so that it applies as a straight fix without
> the cleanups?
>
Okay.



From minwoo.im.dev at gmail.com  Tue Jan 12 04:22:07 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Tue, 12 Jan 2021 18:22:07 +0900
Subject: nvme: enable char device per namespace
In-Reply-To: <20210111185347.oqqzdmoglg3lzo5y@mpHalley.localdomain>
References: <CGME20201216181838eucas1p15c687e5d1319d3fa581990e6cca73295@eucas1p1.samsung.com>
 <20201216181828.21040-1-javier.gonz@samsung.com>
 <20210111185347.oqqzdmoglg3lzo5y@mpHalley.localdomain>
Message-ID: <20210112092207.GA4888@localhost.localdomain>

Hello Javier,

I tested this patch based on nvme-5.11:

[    1.219747] BUG: unable to handle page fault for address: 0000000100000041
[    1.220518] #PF: supervisor read access in kernel mode
[    1.220582] #PF: error_code(0x0000) - not-present page
[    1.220582] PGD 0 P4D 0
[    1.220582] Oops: 0000 [#1] SMP PTI
[    1.220582] CPU: 0 PID: 7 Comm: kworker/u16:0 Not tainted 5.11.0-rc1+ #46
[    1.220582] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.14.0-0-g155821a1990b-prebuilt.qemu.org 04/01/2014
[    1.220582] Workqueue: nvme-wq nvme_scan_work
[    1.220582] RIP: 0010:nvme_ns_id_attrs_are_visible+0x10f/0x152
[    1.220582] Code: 81 7d d0 80 f9 a1 82 74 0a 48 81 7d d0 a0 f9 a1 82 75 50 48 8b 45 e8 48 89 45 f8 48 8b 45 f8 48 83 e8 60 48 8b 80 60 03 00 00 <48> 8b 40 40 48 3d e0 d1 4d 82 74 07 b8 00 00 00 00 eb 2e 48 8b 45
[    1.220582] RSP: 0000:ffffc90000047b70 EFLAGS: 00010282
[    1.220582] RAX: 0000000100000001 RBX: ffffffff824ddb20 RCX: 0000000000000124
[    1.220582] RDX: ffff8881026eac00 RSI: ffffffff82a1f980 RDI: ffff888102745058
[    1.220582] RBP: ffffc90000047ba8 R08: ffff888102948718 R09: 0000000000000000
[    1.220582] R10: 0000000000000000 R11: ffff888100465080 R12: ffff888102745058
[    1.220582] R13: ffff888102948600 R14: 0000000000000000 R15: ffffffff82a1f548
[    1.220582] FS:  0000000000000000(0000) GS:ffff88842fc00000(0000) knlGS:0000000000000000
[    1.220582] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[    1.220582] CR2: 0000000100000041 CR3: 000000000280c001 CR4: 0000000000370ef0
[    1.220582] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[    1.220582] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[    1.220582] Call Trace:
[    1.220582]  internal_create_group+0xde/0x390
[    1.220582]  internal_create_groups.part.4+0x3e/0xa0
[    1.220582]  device_add+0x3cf/0x830
[    1.220582]  ? cdev_get+0x20/0x20
[    1.220582]  ? cdev_purge+0x60/0x60
[    1.220582]  cdev_device_add+0x44/0x70
[    1.220582]  ? cdev_init+0x50/0x60
[    1.220582]  nvme_alloc_chardev_ns+0x187/0x1eb
[    1.220582]  nvme_alloc_ns+0x367/0x460
[    1.220582]  nvme_validate_or_alloc_ns+0xe2/0x139
[    1.220582]  nvme_scan_ns_list+0x113/0x17a
[    1.220582]  nvme_scan_work+0xa5/0x106
[    1.220582]  process_one_work+0x1dd/0x3e0
[    1.220582]  worker_thread+0x2d/0x3b0
[    1.220582]  ? cancel_delayed_work+0x90/0x90
[    1.220582]  kthread+0x117/0x130
[    1.220582]  ? kthread_park+0x90/0x90
[    1.220582]  ret_from_fork+0x22/0x30
[    1.220582] Modules linked in:
[    1.220582] CR2: 0000000100000041
[    1.220582] ---[ end trace b1f509a1bbfbc113 ]---
[    1.220582] RIP: 0010:nvme_ns_id_attrs_are_visible+0x10f/0x152
[    1.220582] Code: 81 7d d0 80 f9 a1 82 74 0a 48 81 7d d0 a0 f9 a1 82 75 50 48 8b 45 e8 48 89 45 f8 48 8b 45 f8 48 83 e8 60 48 8b 80 60 03 00 00 <48> 8b 40 40 48 3d e0 d1 4d 82 74 07 b8 00 00 00 00 eb 2e 48 8b 45
[    1.220582] RSP: 0000:ffffc90000047b70 EFLAGS: 00010282
[    1.220582] RAX: 0000000100000001 RBX: ffffffff824ddb20 RCX: 0000000000000124
[    1.220582] RDX: ffff8881026eac00 RSI: ffffffff82a1f980 RDI: ffff888102745058
[    1.220582] RBP: ffffc90000047ba8 R08: ffff888102948718 R09: 0000000000000000
[    1.220582] R10: 0000000000000000 R11: ffff888100465080 R12: ffff888102745058
[    1.220582] R13: ffff888102948600 R14: 0000000000000000 R15: ffffffff82a1f548
[    1.220582] FS:  0000000000000000(0000) GS:ffff88842fc00000(0000) knlGS:0000000000000000
[    1.220582] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[    1.220582] CR2: 0000000100000041 CR3: 000000000280c001 CR4: 0000000000370ef0
[    1.220582] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[    1.220582] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400

And this happens when CONFIG_NVME_MULTIPATH=y configured.  Please refere
attached log up there :)

Thanks!


From lengchao at huawei.com  Tue Jan 12 04:34:48 2021
From: lengchao at huawei.com (Chao Leng)
Date: Tue, 12 Jan 2021 17:34:48 +0800
Subject: [PATCH 3/3] nvme: add parameter command_retry to enable retry
In-Reply-To: <20210111122748.GA6831@localhost.localdomain>
References: <20210108144659.7126-1-minwoo.im.dev@gmail.com>
 <20210108144659.7126-4-minwoo.im.dev@gmail.com>
 <dfe59030-3eab-a178-7264-792f76dffe4c@huawei.com>
 <20210111122748.GA6831@localhost.localdomain>
Message-ID: <aec841c9-d60c-4ccd-e9ca-731f20accb42@huawei.com>



On 2021/1/11 20:27, Minwoo Im wrote:
> Hello,
> 
> On 21-01-11 11:47:56, Chao Leng wrote:
>>
>>
>> On 2021/1/8 22:46, Minwoo Im wrote:
>>> nvme_init_request() has set REQ_FAILFAST_DRIVER to make requests
>>> non-retryable.  This command flag value is checked in
>>> nvme_decide_disposition() to decide whether to RETRY or other
>>> operations.  In that point, blk_noretry_request() macro will be used to
>>> check if command flags have one of REQ_FAILFAST_*.  If so, it just
>>> decides to complete the request without retrying.
>>>
>>> This patch added a module parameter named command_retry to turn on the
>>> command retry feature in this driver.  If turning it on,
>>> REQ3_FAILFAST_DRIVER will not be set to requests so that retry can be
>>> reached out to nvme_retry_req() based on the module parameter.
>>>
>>> Signed-off-by: Minwoo Im <minwoo.im.dev at gmail.com>
>>> ---
>>>    drivers/nvme/host/core.c | 7 ++++++-
>>>    1 file changed, 6 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
>>> index 6e428fdc25a8..e1836ca9956f 100644
>>> --- a/drivers/nvme/host/core.c
>>> +++ b/drivers/nvme/host/core.c
>>> @@ -44,6 +44,10 @@ static unsigned char shutdown_timeout = 5;
>>>    module_param(shutdown_timeout, byte, 0644);
>>>    MODULE_PARM_DESC(shutdown_timeout, "timeout in seconds for controller shutdown");
>>> +static bool command_retry;
>>> +module_param(command_retry, bool, 0644);
>>> +MODULE_PARM_DESC(command_retry, "retry commands up to nvme_max_retries");
>>> +
>>>    static u8 nvme_max_retries = 5;
>>>    module_param_named(max_retries, nvme_max_retries, byte, 0644);
>>>    MODULE_PARM_DESC(max_retries, "max number of retries a command may have");
>>> @@ -560,7 +564,8 @@ static inline void nvme_init_request(struct request *req,
>>>    	else /* no queuedata implies admin queue */
>>>    		req->timeout = NVME_ADMIN_TIMEOUT;
>>> -	req->cmd_flags |= REQ_FAILFAST_DRIVER;
>>> +	if (!command_retry)
>>> +		req->cmd_flags |= REQ_FAILFAST_DRIVER;
>> In abnormal scenarios, such as request time out, connection process may takes long time or the admin command waits for long time.
>> Retry only for non-host errors may be a better choice. Maybe we can make some optimizations in nvme_decide_disposition.
> 
> Thanks for your review!
> 
> Oh, I agreed that it might wait for so long time in connecting process.
> Restricting some of commands that should be retried would be better as
> you mentiond.
> 
> Do you mean that maybe we can check this module parameter in
> nvme_decide_disposition()?  Like, even if blk_noretry_request(req) says
> that it's non-retriable, if this module parameter is enabled, then we
> can retry rather than failfast?
No, I mean that add the local preferential retry which defined in the NVMe protocol.
---
  drivers/nvme/host/core.c | 18 +++++++++++++-----
  drivers/nvme/host/nvme.h |  1 +
  2 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 99f91efe3824..a25e9b4956b9 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -316,15 +316,20 @@ static inline enum nvme_disposition nvme_decide_disposition(struct request *req)
  	if (likely(nvme_req(req)->status == 0))
  		return COMPLETE;

-	if (blk_noretry_request(req) ||
-	    (nvme_req(req)->status & NVME_SC_DNR) ||
+	if ((nvme_req(req)->status & NVME_SC_DNR) ||
  	    nvme_req(req)->retries >= nvme_max_retries)
  		return COMPLETE;

+	if (nvme_req(req)->ctrl->acre &&
+	    !nvme_is_path_error(nvme_req(req)->status) &&
+	    !blk_queue_dying(req->q))
+		return RETRY;
+
+	if (blk_noretry_request(req))
+		return COMPLETE;
+
  	if (req->cmd_flags & REQ_NVME_MPATH) {
-		if (nvme_is_path_error(nvme_req(req)->status) ||
-		    blk_queue_dying(req->q))
-			return FAILOVER;
+		return FAILOVER;
  	} else {
  		if (blk_queue_dying(req->q))
  			return COMPLETE;
@@ -2513,6 +2518,7 @@ static int nvme_configure_acre(struct nvme_ctrl *ctrl)
  	struct nvme_feat_host_behavior *host;
  	int ret;

+	ctrl->acre = false;
  	/* Don't bother enabling the feature if retry delay is not reported */
  	if (!ctrl->crdt[0])
  		return 0;
@@ -2524,6 +2530,8 @@ static int nvme_configure_acre(struct nvme_ctrl *ctrl)
  	host->acre = NVME_ENABLE_ACRE;
  	ret = nvme_set_features(ctrl, NVME_FEAT_HOST_BEHAVIOR, 0,
  				host, sizeof(*host), NULL);
+	if (!ret)
+		ctrl->acre = true;
  	kfree(host);
  	return ret;
  }
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index bfcedfa4b057..fd914b0dec88 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -276,6 +276,7 @@ struct nvme_ctrl {
  #ifdef CONFIG_BLK_DEV_ZONED
  	u32 max_zone_append;
  #endif
+	bool acre;
  	u16 crdt[3];
  	u16 oncs;
  	u16 oacs;
-- 
> 
> Thanks,
> .
> 


From minwoo.im.dev at gmail.com  Tue Jan 12 06:26:18 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Tue, 12 Jan 2021 20:26:18 +0900
Subject: nvme: enable char device per namespace
In-Reply-To: <20210112092207.GA4888@localhost.localdomain>
References: <CGME20201216181838eucas1p15c687e5d1319d3fa581990e6cca73295@eucas1p1.samsung.com>
 <20201216181828.21040-1-javier.gonz@samsung.com>
 <20210111185347.oqqzdmoglg3lzo5y@mpHalley.localdomain>
 <20210112092207.GA4888@localhost.localdomain>
Message-ID: <20210112112618.GA25093@localhost.localdomain>

On 21-01-12 18:22:07, Minwoo Im wrote:
> Hello Javier,
> 
> I tested this patch based on nvme-5.11:
> 
> [    1.219747] BUG: unable to handle page fault for address: 0000000100000041
> [    1.220518] #PF: supervisor read access in kernel mode
> [    1.220582] #PF: error_code(0x0000) - not-present page
> [    1.220582] PGD 0 P4D 0
> [    1.220582] Oops: 0000 [#1] SMP PTI
> [    1.220582] CPU: 0 PID: 7 Comm: kworker/u16:0 Not tainted 5.11.0-rc1+ #46
> [    1.220582] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.14.0-0-g155821a1990b-prebuilt.qemu.org 04/01/2014
> [    1.220582] Workqueue: nvme-wq nvme_scan_work
> [    1.220582] RIP: 0010:nvme_ns_id_attrs_are_visible+0x10f/0x152
> [    1.220582] Code: 81 7d d0 80 f9 a1 82 74 0a 48 81 7d d0 a0 f9 a1 82 75 50 48 8b 45 e8 48 89 45 f8 48 8b 45 f8 48 83 e8 60 48 8b 80 60 03 00 00 <48> 8b 40 40 48 3d e0 d1 4d 82 74 07 b8 00 00 00 00 eb 2e 48 8b 45
> [    1.220582] RSP: 0000:ffffc90000047b70 EFLAGS: 00010282
> [    1.220582] RAX: 0000000100000001 RBX: ffffffff824ddb20 RCX: 0000000000000124
> [    1.220582] RDX: ffff8881026eac00 RSI: ffffffff82a1f980 RDI: ffff888102745058
> [    1.220582] RBP: ffffc90000047ba8 R08: ffff888102948718 R09: 0000000000000000
> [    1.220582] R10: 0000000000000000 R11: ffff888100465080 R12: ffff888102745058
> [    1.220582] R13: ffff888102948600 R14: 0000000000000000 R15: ffffffff82a1f548
> [    1.220582] FS:  0000000000000000(0000) GS:ffff88842fc00000(0000) knlGS:0000000000000000
> [    1.220582] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [    1.220582] CR2: 0000000100000041 CR3: 000000000280c001 CR4: 0000000000370ef0
> [    1.220582] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> [    1.220582] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
> [    1.220582] Call Trace:
> [    1.220582]  internal_create_group+0xde/0x390
> [    1.220582]  internal_create_groups.part.4+0x3e/0xa0
> [    1.220582]  device_add+0x3cf/0x830
> [    1.220582]  ? cdev_get+0x20/0x20
> [    1.220582]  ? cdev_purge+0x60/0x60
> [    1.220582]  cdev_device_add+0x44/0x70
> [    1.220582]  ? cdev_init+0x50/0x60
> [    1.220582]  nvme_alloc_chardev_ns+0x187/0x1eb
> [    1.220582]  nvme_alloc_ns+0x367/0x460
> [    1.220582]  nvme_validate_or_alloc_ns+0xe2/0x139
> [    1.220582]  nvme_scan_ns_list+0x113/0x17a
> [    1.220582]  nvme_scan_work+0xa5/0x106
> [    1.220582]  process_one_work+0x1dd/0x3e0
> [    1.220582]  worker_thread+0x2d/0x3b0
> [    1.220582]  ? cancel_delayed_work+0x90/0x90
> [    1.220582]  kthread+0x117/0x130
> [    1.220582]  ? kthread_park+0x90/0x90
> [    1.220582]  ret_from_fork+0x22/0x30
> [    1.220582] Modules linked in:
> [    1.220582] CR2: 0000000100000041
> [    1.220582] ---[ end trace b1f509a1bbfbc113 ]---
> [    1.220582] RIP: 0010:nvme_ns_id_attrs_are_visible+0x10f/0x152
> [    1.220582] Code: 81 7d d0 80 f9 a1 82 74 0a 48 81 7d d0 a0 f9 a1 82 75 50 48 8b 45 e8 48 89 45 f8 48 8b 45 f8 48 83 e8 60 48 8b 80 60 03 00 00 <48> 8b 40 40 48 3d e0 d1 4d 82 74 07 b8 00 00 00 00 eb 2e 48 8b 45
> [    1.220582] RSP: 0000:ffffc90000047b70 EFLAGS: 00010282
> [    1.220582] RAX: 0000000100000001 RBX: ffffffff824ddb20 RCX: 0000000000000124
> [    1.220582] RDX: ffff8881026eac00 RSI: ffffffff82a1f980 RDI: ffff888102745058
> [    1.220582] RBP: ffffc90000047ba8 R08: ffff888102948718 R09: 0000000000000000
> [    1.220582] R10: 0000000000000000 R11: ffff888100465080 R12: ffff888102745058
> [    1.220582] R13: ffff888102948600 R14: 0000000000000000 R15: ffffffff82a1f548
> [    1.220582] FS:  0000000000000000(0000) GS:ffff88842fc00000(0000) knlGS:0000000000000000
> [    1.220582] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [    1.220582] CR2: 0000000100000041 CR3: 000000000280c001 CR4: 0000000000370ef0
> [    1.220582] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> [    1.220582] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
> 
> And this happens when CONFIG_NVME_MULTIPATH=y configured.  Please refere
> attached log up there :)
> 
> Thanks!

If this chardev has to have ns_id_attr_group, we need to consider
nvme_ns_id_attrs_are_visible() to take care of dev_to_disk(dev) in case
non-block device.

Thanks!


From minwoo.im.dev at gmail.com  Tue Jan 12 06:28:19 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Tue, 12 Jan 2021 20:28:19 +0900
Subject: [PATCH 3/3] nvme: add parameter command_retry to enable retry
In-Reply-To: <aec841c9-d60c-4ccd-e9ca-731f20accb42@huawei.com>
References: <20210108144659.7126-1-minwoo.im.dev@gmail.com>
 <20210108144659.7126-4-minwoo.im.dev@gmail.com>
 <dfe59030-3eab-a178-7264-792f76dffe4c@huawei.com>
 <20210111122748.GA6831@localhost.localdomain>
 <aec841c9-d60c-4ccd-e9ca-731f20accb42@huawei.com>
Message-ID: <20210112112819.GB25093@localhost.localdomain>

Hello,

On 21-01-12 17:34:48, Chao Leng wrote:
> 
> 
> On 2021/1/11 20:27, Minwoo Im wrote:
> > Hello,
> > 
> > On 21-01-11 11:47:56, Chao Leng wrote:
> > > 
> > > 
> > > On 2021/1/8 22:46, Minwoo Im wrote:
> > > > nvme_init_request() has set REQ_FAILFAST_DRIVER to make requests
> > > > non-retryable.  This command flag value is checked in
> > > > nvme_decide_disposition() to decide whether to RETRY or other
> > > > operations.  In that point, blk_noretry_request() macro will be used to
> > > > check if command flags have one of REQ_FAILFAST_*.  If so, it just
> > > > decides to complete the request without retrying.
> > > > 
> > > > This patch added a module parameter named command_retry to turn on the
> > > > command retry feature in this driver.  If turning it on,
> > > > REQ3_FAILFAST_DRIVER will not be set to requests so that retry can be
> > > > reached out to nvme_retry_req() based on the module parameter.
> > > > 
> > > > Signed-off-by: Minwoo Im <minwoo.im.dev at gmail.com>
> > > > ---
> > > >    drivers/nvme/host/core.c | 7 ++++++-
> > > >    1 file changed, 6 insertions(+), 1 deletion(-)
> > > > 
> > > > diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
> > > > index 6e428fdc25a8..e1836ca9956f 100644
> > > > --- a/drivers/nvme/host/core.c
> > > > +++ b/drivers/nvme/host/core.c
> > > > @@ -44,6 +44,10 @@ static unsigned char shutdown_timeout = 5;
> > > >    module_param(shutdown_timeout, byte, 0644);
> > > >    MODULE_PARM_DESC(shutdown_timeout, "timeout in seconds for controller shutdown");
> > > > +static bool command_retry;
> > > > +module_param(command_retry, bool, 0644);
> > > > +MODULE_PARM_DESC(command_retry, "retry commands up to nvme_max_retries");
> > > > +
> > > >    static u8 nvme_max_retries = 5;
> > > >    module_param_named(max_retries, nvme_max_retries, byte, 0644);
> > > >    MODULE_PARM_DESC(max_retries, "max number of retries a command may have");
> > > > @@ -560,7 +564,8 @@ static inline void nvme_init_request(struct request *req,
> > > >    	else /* no queuedata implies admin queue */
> > > >    		req->timeout = NVME_ADMIN_TIMEOUT;
> > > > -	req->cmd_flags |= REQ_FAILFAST_DRIVER;
> > > > +	if (!command_retry)
> > > > +		req->cmd_flags |= REQ_FAILFAST_DRIVER;
> > > In abnormal scenarios, such as request time out, connection process may takes long time or the admin command waits for long time.
> > > Retry only for non-host errors may be a better choice. Maybe we can make some optimizations in nvme_decide_disposition.
> > 
> > Thanks for your review!
> > 
> > Oh, I agreed that it might wait for so long time in connecting process.
> > Restricting some of commands that should be retried would be better as
> > you mentiond.
> > 
> > Do you mean that maybe we can check this module parameter in
> > nvme_decide_disposition()?  Like, even if blk_noretry_request(req) says
> > that it's non-retriable, if this module parameter is enabled, then we
> > can retry rather than failfast?
> No, I mean that add the local preferential retry which defined in the NVMe protocol.

Thanks for your suggestion, Chao.  I think this is much better idea than
module parameter.  Fixing the nvme_decide_disposition() would be better!
I think it's going to be also an answer for Christoph's question on this
patch.  Please let me prepare next pach series.

Thanks,


From sashal at kernel.org  Tue Jan 12 07:55:20 2021
From: sashal at kernel.org (Sasha Levin)
Date: Tue, 12 Jan 2021 07:55:20 -0500
Subject: [PATCH AUTOSEL 5.10 38/51] nvme-pci: mark Samsung PM1725a as
 IGNORE_DEV_SUBNQN
In-Reply-To: <20210112125534.70280-1-sashal@kernel.org>
References: <20210112125534.70280-1-sashal@kernel.org>
Message-ID: <20210112125534.70280-38-sashal@kernel.org>

From: Gopal Tiwari <gtiwari at redhat.com>

[ Upstream commit 7ee5c78ca3895d44e918c38332921983ed678be0 ]

A system with more than one of these SSDs will only have one usable.
Hence the kernel fails to detect nvme devices due to duplicate cntlids.

[    6.274554] nvme nvme1: Duplicate cntlid 33 with nvme0, rejecting
[    6.274566] nvme nvme1: Removing after probe failure status: -22

Adding the NVME_QUIRK_IGNORE_DEV_SUBNQN quirk to resolves the issue.

Signed-off-by: Gopal Tiwari <gtiwari at redhat.com>
Signed-off-by: Christoph Hellwig <hch at lst.de>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/nvme/host/pci.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 3be352403839a..143f16a9f8d7e 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -3201,7 +3201,8 @@ static const struct pci_device_id nvme_id_table[] = {
 	{ PCI_DEVICE(0x144d, 0xa821),   /* Samsung PM1725 */
 		.driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, },
 	{ PCI_DEVICE(0x144d, 0xa822),   /* Samsung PM1725a */
-		.driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, },
+		.driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY |
+				NVME_QUIRK_IGNORE_DEV_SUBNQN, },
 	{ PCI_DEVICE(0x1d1d, 0x1f1f),	/* LighNVM qemu device */
 		.driver_data = NVME_QUIRK_LIGHTNVM, },
 	{ PCI_DEVICE(0x1d1d, 0x2807),	/* CNEX WL */
-- 
2.27.0



From sashal at kernel.org  Tue Jan 12 07:55:21 2021
From: sashal at kernel.org (Sasha Levin)
Date: Tue, 12 Jan 2021 07:55:21 -0500
Subject: [PATCH AUTOSEL 5.10 39/51] nvme: avoid possible double fetch in
 handling CQE
In-Reply-To: <20210112125534.70280-1-sashal@kernel.org>
References: <20210112125534.70280-1-sashal@kernel.org>
Message-ID: <20210112125534.70280-39-sashal@kernel.org>

From: Lalithambika Krishnakumar <lalithambika.krishnakumar at intel.com>

[ Upstream commit 62df80165d7f197c9c0652e7416164f294a96661 ]

While handling the completion queue, keep a local copy of the command id
from the DMA-accessible completion entry. This silences a time-of-check
to time-of-use (TOCTOU) warning from KF/x[1], with respect to a
Thunderclap[2] vulnerability analysis. The double-read impact appears
benign.

There may be a theoretical window for @command_id to be used as an
adversary-controlled array-index-value for mounting a speculative
execution attack, but that mitigation is saved for a potential follow-on.
A man-in-the-middle attack on the data payload is out of scope for this
analysis and is hopefully mitigated by filesystem integrity mechanisms.

[1] https://github.com/intel/kernel-fuzzer-for-xen-project
[2] http://thunderclap.io/thunderclap-paper-ndss2019.pdf
Signed-off-by: Lalithambika Krishna Kumar <lalithambika.krishnakumar at intel.com>
Signed-off-by: Christoph Hellwig <hch at lst.de>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/nvme/host/pci.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 143f16a9f8d7e..a89d74c5cd1a7 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -967,6 +967,7 @@ static inline struct blk_mq_tags *nvme_queue_tagset(struct nvme_queue *nvmeq)
 static inline void nvme_handle_cqe(struct nvme_queue *nvmeq, u16 idx)
 {
 	struct nvme_completion *cqe = &nvmeq->cqes[idx];
+	__u16 command_id = READ_ONCE(cqe->command_id);
 	struct request *req;
 
 	/*
@@ -975,17 +976,17 @@ static inline void nvme_handle_cqe(struct nvme_queue *nvmeq, u16 idx)
 	 * aborts.  We don't even bother to allocate a struct request
 	 * for them but rather special case them here.
 	 */
-	if (unlikely(nvme_is_aen_req(nvmeq->qid, cqe->command_id))) {
+	if (unlikely(nvme_is_aen_req(nvmeq->qid, command_id))) {
 		nvme_complete_async_event(&nvmeq->dev->ctrl,
 				cqe->status, &cqe->result);
 		return;
 	}
 
-	req = blk_mq_tag_to_rq(nvme_queue_tagset(nvmeq), cqe->command_id);
+	req = blk_mq_tag_to_rq(nvme_queue_tagset(nvmeq), command_id);
 	if (unlikely(!req)) {
 		dev_warn(nvmeq->dev->ctrl.device,
 			"invalid id %d completed on queue %d\n",
-			cqe->command_id, le16_to_cpu(cqe->sq_id));
+			command_id, le16_to_cpu(cqe->sq_id));
 		return;
 	}
 
-- 
2.27.0



From sashal at kernel.org  Tue Jan 12 07:55:22 2021
From: sashal at kernel.org (Sasha Levin)
Date: Tue, 12 Jan 2021 07:55:22 -0500
Subject: [PATCH AUTOSEL 5.10 40/51] nvmet-rdma: Fix list_del corruption on
 queue establishment failure
In-Reply-To: <20210112125534.70280-1-sashal@kernel.org>
References: <20210112125534.70280-1-sashal@kernel.org>
Message-ID: <20210112125534.70280-40-sashal@kernel.org>

From: Israel Rukshin <israelr at nvidia.com>

[ Upstream commit 9ceb7863537748c67fa43ac4f2f565819bbd36e4 ]

When a queue is in NVMET_RDMA_Q_CONNECTING state, it may has some
requests at rsp_wait_list. In case a disconnect occurs at this
state, no one will empty this list and will return the requests to
free_rsps list. Normally nvmet_rdma_queue_established() free those
requests after moving the queue to NVMET_RDMA_Q_LIVE state, but in
this case __nvmet_rdma_queue_disconnect() is called before. The
crash happens at nvmet_rdma_free_rsps() when calling
list_del(&rsp->free_list), because the request exists only at
the wait list. To fix the issue, simply clear rsp_wait_list when
destroying the queue.

Signed-off-by: Israel Rukshin <israelr at nvidia.com>
Reviewed-by: Max Gurtovoy <mgurtovoy at nvidia.com>
Signed-off-by: Christoph Hellwig <hch at lst.de>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/nvme/target/rdma.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c
index 5c1e7cb7fe0de..bdfc22eb2a10f 100644
--- a/drivers/nvme/target/rdma.c
+++ b/drivers/nvme/target/rdma.c
@@ -1641,6 +1641,16 @@ static void __nvmet_rdma_queue_disconnect(struct nvmet_rdma_queue *queue)
 	spin_lock_irqsave(&queue->state_lock, flags);
 	switch (queue->state) {
 	case NVMET_RDMA_Q_CONNECTING:
+		while (!list_empty(&queue->rsp_wait_list)) {
+			struct nvmet_rdma_rsp *rsp;
+
+			rsp = list_first_entry(&queue->rsp_wait_list,
+					       struct nvmet_rdma_rsp,
+					       wait_list);
+			list_del(&rsp->wait_list);
+			nvmet_rdma_put_rsp(rsp);
+		}
+		fallthrough;
 	case NVMET_RDMA_Q_LIVE:
 		queue->state = NVMET_RDMA_Q_DISCONNECTING;
 		disconnect = true;
-- 
2.27.0



From sashal at kernel.org  Tue Jan 12 07:56:38 2021
From: sashal at kernel.org (Sasha Levin)
Date: Tue, 12 Jan 2021 07:56:38 -0500
Subject: [PATCH AUTOSEL 5.4 22/28] nvme-pci: mark Samsung PM1725a as
 IGNORE_DEV_SUBNQN
In-Reply-To: <20210112125645.70739-1-sashal@kernel.org>
References: <20210112125645.70739-1-sashal@kernel.org>
Message-ID: <20210112125645.70739-22-sashal@kernel.org>

From: Gopal Tiwari <gtiwari at redhat.com>

[ Upstream commit 7ee5c78ca3895d44e918c38332921983ed678be0 ]

A system with more than one of these SSDs will only have one usable.
Hence the kernel fails to detect nvme devices due to duplicate cntlids.

[    6.274554] nvme nvme1: Duplicate cntlid 33 with nvme0, rejecting
[    6.274566] nvme nvme1: Removing after probe failure status: -22

Adding the NVME_QUIRK_IGNORE_DEV_SUBNQN quirk to resolves the issue.

Signed-off-by: Gopal Tiwari <gtiwari at redhat.com>
Signed-off-by: Christoph Hellwig <hch at lst.de>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/nvme/host/pci.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 9b1fc8633cfe1..ef93bd3ed339c 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -3145,7 +3145,8 @@ static const struct pci_device_id nvme_id_table[] = {
 	{ PCI_DEVICE(0x144d, 0xa821),   /* Samsung PM1725 */
 		.driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, },
 	{ PCI_DEVICE(0x144d, 0xa822),   /* Samsung PM1725a */
-		.driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, },
+		.driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY |
+				NVME_QUIRK_IGNORE_DEV_SUBNQN, },
 	{ PCI_DEVICE(0x1d1d, 0x1f1f),	/* LighNVM qemu device */
 		.driver_data = NVME_QUIRK_LIGHTNVM, },
 	{ PCI_DEVICE(0x1d1d, 0x2807),	/* CNEX WL */
-- 
2.27.0



From sashal at kernel.org  Tue Jan 12 07:56:39 2021
From: sashal at kernel.org (Sasha Levin)
Date: Tue, 12 Jan 2021 07:56:39 -0500
Subject: [PATCH AUTOSEL 5.4 23/28] nvmet-rdma: Fix list_del corruption on
 queue establishment failure
In-Reply-To: <20210112125645.70739-1-sashal@kernel.org>
References: <20210112125645.70739-1-sashal@kernel.org>
Message-ID: <20210112125645.70739-23-sashal@kernel.org>

From: Israel Rukshin <israelr at nvidia.com>

[ Upstream commit 9ceb7863537748c67fa43ac4f2f565819bbd36e4 ]

When a queue is in NVMET_RDMA_Q_CONNECTING state, it may has some
requests at rsp_wait_list. In case a disconnect occurs at this
state, no one will empty this list and will return the requests to
free_rsps list. Normally nvmet_rdma_queue_established() free those
requests after moving the queue to NVMET_RDMA_Q_LIVE state, but in
this case __nvmet_rdma_queue_disconnect() is called before. The
crash happens at nvmet_rdma_free_rsps() when calling
list_del(&rsp->free_list), because the request exists only at
the wait list. To fix the issue, simply clear rsp_wait_list when
destroying the queue.

Signed-off-by: Israel Rukshin <israelr at nvidia.com>
Reviewed-by: Max Gurtovoy <mgurtovoy at nvidia.com>
Signed-off-by: Christoph Hellwig <hch at lst.de>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/nvme/target/rdma.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c
index b5314164479e9..50e2007092bc0 100644
--- a/drivers/nvme/target/rdma.c
+++ b/drivers/nvme/target/rdma.c
@@ -1351,6 +1351,16 @@ static void __nvmet_rdma_queue_disconnect(struct nvmet_rdma_queue *queue)
 	spin_lock_irqsave(&queue->state_lock, flags);
 	switch (queue->state) {
 	case NVMET_RDMA_Q_CONNECTING:
+		while (!list_empty(&queue->rsp_wait_list)) {
+			struct nvmet_rdma_rsp *rsp;
+
+			rsp = list_first_entry(&queue->rsp_wait_list,
+					       struct nvmet_rdma_rsp,
+					       wait_list);
+			list_del(&rsp->wait_list);
+			nvmet_rdma_put_rsp(rsp);
+		}
+		fallthrough;
 	case NVMET_RDMA_Q_LIVE:
 		queue->state = NVMET_RDMA_Q_DISCONNECTING;
 		disconnect = true;
-- 
2.27.0



From elad.grupi at dell.com  Tue Jan 12 09:00:15 2021
From: elad.grupi at dell.com (elad.grupi at dell.com)
Date: Tue, 12 Jan 2021 16:00:15 +0200
Subject: [PATCH] nvme-tcp: fix a segmentation fault during io parsing error
Message-ID: <20210112140015.79743-1-elad.grupi@dell.com>

From: Elad Grupi <Elad.Grupi at emc.com>

In case there is an io that contains inline data and it goes to
parsing error flow, command response will free command and iov
before clearing the data on the socket buffer.
This will delay the command response until receive flow is completed.

Signed-off-by: Elad Grupi <Elad.Grupi at emc.com>
---
 drivers/nvme/target/tcp.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
index d535080b781f..dea94da4c9ba 100644
--- a/drivers/nvme/target/tcp.c
+++ b/drivers/nvme/target/tcp.c
@@ -146,6 +146,7 @@ static struct workqueue_struct *nvmet_tcp_wq;
 static struct nvmet_fabrics_ops nvmet_tcp_ops;
 static void nvmet_tcp_free_cmd(struct nvmet_tcp_cmd *c);
 static void nvmet_tcp_finish_cmd(struct nvmet_tcp_cmd *cmd);
+static void nvmet_tcp_queue_response(struct nvmet_req *req);
 
 static inline u16 nvmet_tcp_cmd_tag(struct nvmet_tcp_queue *queue,
 		struct nvmet_tcp_cmd *cmd)
@@ -476,7 +477,11 @@ static struct nvmet_tcp_cmd *nvmet_tcp_fetch_cmd(struct nvmet_tcp_queue *queue)
 		nvmet_setup_c2h_data_pdu(queue->snd_cmd);
 	else if (nvmet_tcp_need_data_in(queue->snd_cmd))
 		nvmet_setup_r2t_pdu(queue->snd_cmd);
-	else
+	else if (nvmet_tcp_has_data_in(queue->snd_cmd) &&
+			nvmet_tcp_has_inline_data(queue->snd_cmd)) {
+		nvmet_tcp_queue_response(&queue->snd_cmd->req);
+		queue->snd_cmd = NULL;
+	} else
 		nvmet_setup_response_pdu(queue->snd_cmd);
 
 	return queue->snd_cmd;
-- 
2.16.5



From revanth.rajashekar at intel.com  Tue Jan 12 12:29:41 2021
From: revanth.rajashekar at intel.com (Revanth Rajashekar)
Date: Tue, 12 Jan 2021 10:29:41 -0700
Subject: [PATCH v2] nvme: Check the PRINFO bit and the Metadata size before
 deciding the host buffer length
Message-ID: <20210112172941.3911-1-revanth.rajashekar@intel.com>

According to NVMe spec v1.4, section 8.3.1, the PRINFO bit and
the metadata size play a vital role in deteriming the host buffer size.

If PRIFNO bit is set and MS==8, the host doesn't add the metadata buffer,
instead the controller adds it.

Changes from v1:
1. Remove the definition 'NVME_PRINFO_CTRL_BIT'
2. Remove variable 'control'
3. Remove test_bit and check the bit with the CPU arch's native endianness

Signed-off-by: Revanth Rajashekar <revanth.rajashekar at intel.com>
---
 drivers/nvme/host/core.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index f320273fc672..03261e0abdcc 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -1546,6 +1546,11 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
 	meta_len = (io.nblocks + 1) * ns->ms;
 	metadata = nvme_to_user_ptr(io.metadata);

+	if (io.control & NVME_RW_PRINFO_PRACT && ns->ms == 8) {
+		meta_len = 0;
+		metadata = NULL;
+	}
+
 	if (ns->features & NVME_NS_EXT_LBAS) {
 		length += meta_len;
 		meta_len = 0;
--
2.17.1



From javier at javigon.com  Tue Jan 12 13:30:55 2021
From: javier at javigon.com (Javier =?utf-8?B?R29uesOhbGV6?=)
Date: Tue, 12 Jan 2021 19:30:55 +0100
Subject: nvme: enable char device per namespace
In-Reply-To: <20210112092207.GA4888@localhost.localdomain>
References: <CGME20201216181838eucas1p15c687e5d1319d3fa581990e6cca73295@eucas1p1.samsung.com>
 <20201216181828.21040-1-javier.gonz@samsung.com>
 <20210111185347.oqqzdmoglg3lzo5y@mpHalley.localdomain>
 <20210112092207.GA4888@localhost.localdomain>
Message-ID: <20210112183055.u3y34tfxh4d5aeue@unifi>

On 12.01.2021 18:22, Minwoo Im wrote:
>Hello Javier,
>
>I tested this patch based on nvme-5.11:
>
>[    1.219747] BUG: unable to handle page fault for address: 0000000100000041
>[    1.220518] #PF: supervisor read access in kernel mode
>[    1.220582] #PF: error_code(0x0000) - not-present page
>[    1.220582] PGD 0 P4D 0
>[    1.220582] Oops: 0000 [#1] SMP PTI
>[    1.220582] CPU: 0 PID: 7 Comm: kworker/u16:0 Not tainted 5.11.0-rc1+ #46
>[    1.220582] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.14.0-0-g155821a1990b-prebuilt.qemu.org 04/01/2014
>[    1.220582] Workqueue: nvme-wq nvme_scan_work
>[    1.220582] RIP: 0010:nvme_ns_id_attrs_are_visible+0x10f/0x152
>[    1.220582] Code: 81 7d d0 80 f9 a1 82 74 0a 48 81 7d d0 a0 f9 a1 82 75 50 48 8b 45 e8 48 89 45 f8 48 8b 45 f8 48 83 e8 60 48 8b 80 60 03 00 00 <48> 8b 40 40 48 3d e0 d1 4d 82 74 07 b8 00 00 00 00 eb 2e 48 8b 45
>[    1.220582] RSP: 0000:ffffc90000047b70 EFLAGS: 00010282
>[    1.220582] RAX: 0000000100000001 RBX: ffffffff824ddb20 RCX: 0000000000000124
>[    1.220582] RDX: ffff8881026eac00 RSI: ffffffff82a1f980 RDI: ffff888102745058
>[    1.220582] RBP: ffffc90000047ba8 R08: ffff888102948718 R09: 0000000000000000
>[    1.220582] R10: 0000000000000000 R11: ffff888100465080 R12: ffff888102745058
>[    1.220582] R13: ffff888102948600 R14: 0000000000000000 R15: ffffffff82a1f548
>[    1.220582] FS:  0000000000000000(0000) GS:ffff88842fc00000(0000) knlGS:0000000000000000
>[    1.220582] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>[    1.220582] CR2: 0000000100000041 CR3: 000000000280c001 CR4: 0000000000370ef0
>[    1.220582] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
>[    1.220582] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
>[    1.220582] Call Trace:
>[    1.220582]  internal_create_group+0xde/0x390
>[    1.220582]  internal_create_groups.part.4+0x3e/0xa0
>[    1.220582]  device_add+0x3cf/0x830
>[    1.220582]  ? cdev_get+0x20/0x20
>[    1.220582]  ? cdev_purge+0x60/0x60
>[    1.220582]  cdev_device_add+0x44/0x70
>[    1.220582]  ? cdev_init+0x50/0x60
>[    1.220582]  nvme_alloc_chardev_ns+0x187/0x1eb
>[    1.220582]  nvme_alloc_ns+0x367/0x460
>[    1.220582]  nvme_validate_or_alloc_ns+0xe2/0x139
>[    1.220582]  nvme_scan_ns_list+0x113/0x17a
>[    1.220582]  nvme_scan_work+0xa5/0x106
>[    1.220582]  process_one_work+0x1dd/0x3e0
>[    1.220582]  worker_thread+0x2d/0x3b0
>[    1.220582]  ? cancel_delayed_work+0x90/0x90
>[    1.220582]  kthread+0x117/0x130
>[    1.220582]  ? kthread_park+0x90/0x90
>[    1.220582]  ret_from_fork+0x22/0x30
>[    1.220582] Modules linked in:
>[    1.220582] CR2: 0000000100000041
>[    1.220582] ---[ end trace b1f509a1bbfbc113 ]---
>[    1.220582] RIP: 0010:nvme_ns_id_attrs_are_visible+0x10f/0x152
>[    1.220582] Code: 81 7d d0 80 f9 a1 82 74 0a 48 81 7d d0 a0 f9 a1 82 75 50 48 8b 45 e8 48 89 45 f8 48 8b 45 f8 48 83 e8 60 48 8b 80 60 03 00 00 <48> 8b 40 40 48 3d e0 d1 4d 82 74 07 b8 00 00 00 00 eb 2e 48 8b 45
>[    1.220582] RSP: 0000:ffffc90000047b70 EFLAGS: 00010282
>[    1.220582] RAX: 0000000100000001 RBX: ffffffff824ddb20 RCX: 0000000000000124
>[    1.220582] RDX: ffff8881026eac00 RSI: ffffffff82a1f980 RDI: ffff888102745058
>[    1.220582] RBP: ffffc90000047ba8 R08: ffff888102948718 R09: 0000000000000000
>[    1.220582] R10: 0000000000000000 R11: ffff888100465080 R12: ffff888102745058
>[    1.220582] R13: ffff888102948600 R14: 0000000000000000 R15: ffffffff82a1f548
>[    1.220582] FS:  0000000000000000(0000) GS:ffff88842fc00000(0000) knlGS:0000000000000000
>[    1.220582] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>[    1.220582] CR2: 0000000100000041 CR3: 000000000280c001 CR4: 0000000000370ef0
>[    1.220582] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
>[    1.220582] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
>
>And this happens when CONFIG_NVME_MULTIPATH=y configured.  Please refere
>attached log up there :)
>
>Thanks!

I have not implemented multipath support, but it should definitely not
crash like this. I'll rebase to 5.11 and test.

Christoph: Is it OK to send this without multipath or should I just send
all together?

Javier


From hch at lst.de  Tue Jan 12 13:33:03 2021
From: hch at lst.de (Christoph Hellwig)
Date: Tue, 12 Jan 2021 19:33:03 +0100
Subject: nvme: enable char device per namespace
In-Reply-To: <20210112183055.u3y34tfxh4d5aeue@unifi>
References: <CGME20201216181838eucas1p15c687e5d1319d3fa581990e6cca73295@eucas1p1.samsung.com>
 <20201216181828.21040-1-javier.gonz@samsung.com>
 <20210111185347.oqqzdmoglg3lzo5y@mpHalley.localdomain>
 <20210112092207.GA4888@localhost.localdomain>
 <20210112183055.u3y34tfxh4d5aeue@unifi>
Message-ID: <20210112183303.GA5050@lst.de>

On Tue, Jan 12, 2021 at 07:30:55PM +0100, Javier Gonz?lez wrote:
> I have not implemented multipath support, but it should definitely not
> crash like this. I'll rebase to 5.11 and test.
>
> Christoph: Is it OK to send this without multipath or should I just send
> all together?

We're not in a rush at the moment, so I'd prefer working multipath
support if you can spare a few cycles.


From hch at lst.de  Tue Jan 12 13:39:11 2021
From: hch at lst.de (Christoph Hellwig)
Date: Tue, 12 Jan 2021 19:39:11 +0100
Subject: [PATCH v2] nvme: Check the PRINFO bit and the Metadata size
 before deciding the host buffer length
In-Reply-To: <20210112172941.3911-1-revanth.rajashekar@intel.com>
References: <20210112172941.3911-1-revanth.rajashekar@intel.com>
Message-ID: <20210112183911.GB5050@lst.de>

> @@ -1546,6 +1546,11 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
>  	meta_len = (io.nblocks + 1) * ns->ms;
>  	metadata = nvme_to_user_ptr(io.metadata);
> 
> +	if (io.control & NVME_RW_PRINFO_PRACT && ns->ms == 8) {
> +		meta_len = 0;
> +		metadata = NULL;
> +	}
> +

Wouldn't something like:

	if ((io.control & NVME_RW_PRINFO_PRACT) &&
	    ns->ms == sizeof(struct t10_pi_tuple)) {
		/*
		 * Protection information is stripped/inserted by the
		 * controller.
		 */
		if (nvme_to_user_ptr(io.metadata))
			return -EINVAL;
		meta_len = 0;
		metadata = NULL;
	} else {
	 	meta_len = (io.nblocks + 1) * ns->ms;
		metadata = nvme_to_user_ptr(io.metadata);
	}

make a little more sense?


From javier at javigon.com  Tue Jan 12 13:41:08 2021
From: javier at javigon.com (Javier =?utf-8?B?R29uesOhbGV6?=)
Date: Tue, 12 Jan 2021 19:41:08 +0100
Subject: nvme: enable char device per namespace
In-Reply-To: <20210112183303.GA5050@lst.de>
References: <CGME20201216181838eucas1p15c687e5d1319d3fa581990e6cca73295@eucas1p1.samsung.com>
 <20201216181828.21040-1-javier.gonz@samsung.com>
 <20210111185347.oqqzdmoglg3lzo5y@mpHalley.localdomain>
 <20210112092207.GA4888@localhost.localdomain>
 <20210112183055.u3y34tfxh4d5aeue@unifi>
 <20210112183303.GA5050@lst.de>
Message-ID: <20210112184108.x42fhpdtfn2a24wz@unifi>

On 12.01.2021 19:33, Christoph Hellwig wrote:
>On Tue, Jan 12, 2021 at 07:30:55PM +0100, Javier Gonz?lez wrote:
>> I have not implemented multipath support, but it should definitely not
>> crash like this. I'll rebase to 5.11 and test.
>>
>> Christoph: Is it OK to send this without multipath or should I just send
>> all together?
>
>We're not in a rush at the moment, so I'd prefer working multipath
>support if you can spare a few cycles.

Sure. I'll work on that and submit all under the same patchset.


From chaitanya.kulkarni at wdc.com  Tue Jan 12 16:14:06 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Tue, 12 Jan 2021 13:14:06 -0800
Subject: [V3 0/4] nvmet: admin-cmd related cleanups and a fix  
Message-ID: <20210112211410.24742-1-chaitanya.kulkarni@wdc.com>

Hi,

There are three functions where local variable ns is used instead of
using req->ns which leads to duplicate nvmet_put_namespace() calls.
We can just use req->ns and not the local variable to avoid duplicate
calls. First three patches fix that.

The first patch sets the right error status code when namespace is not
found in nvmet_execute_identify_ns().

I've tested this series with nvme blktests, all the testcases are
passing.

-ck

Changes from V2:-

1. Rebase and retest on the latest nvme-5.11.
2. Add ns status error patch at the front of the series.

Changes from V1:-

1. Rebase and retest on the latest nvme-5.11.

Chaitanya Kulkarni (4):
  nvmet: set right status on error in id-ns handler
  nvmet: remove extra variable in smart log nsid
  nvmet: remove extra variable in id-desclist
  nvmet: remove extra variable in identify ns

 drivers/nvme/target/admin-cmd.c | 74 ++++++++++++++++-----------------
 1 file changed, 36 insertions(+), 38 deletions(-)

# !./check
./check tests/nvme
nvme/002 (create many subsystems and test discovery)         [passed]
    runtime    ...  27.806s
nvme/003 (test if we're sending keep-alives to a discovery controller) [passed]
    runtime  10.143s  ...  10.136s
nvme/004 (test nvme and nvmet UUID NS descriptors)           [passed]
    runtime  1.697s  ...  1.730s
nvme/005 (reset local loopback target)                       [not run]
    nvme_core module does not have parameter multipath
nvme/006 (create an NVMeOF target with a block device-backed ns) [passed]
    runtime  0.115s  ...  0.113s
nvme/007 (create an NVMeOF target with a file-backed ns)     [passed]
    runtime  0.072s  ...  0.074s
nvme/008 (create an NVMeOF host with a block device-backed ns) [passed]
    runtime  1.740s  ...  1.720s
nvme/009 (create an NVMeOF host with a file-backed ns)       [passed]
    runtime  1.671s  ...  1.683s
nvme/010 (run data verification fio job on NVMeOF block device-backed ns) [passed]
    runtime  19.842s  ...  25.213s
nvme/011 (run data verification fio job on NVMeOF file-backed ns) [passed]
    runtime  232.526s  ...  257.846s
nvme/012 (run mkfs and data verification fio job on NVMeOF block device-backed ns) [passed]
    runtime  46.703s  ...  47.453s
nvme/013 (run mkfs and data verification fio job on NVMeOF file-backed ns) [passed]
    runtime  284.149s  ...  249.408s
nvme/014 (flush a NVMeOF block device-backed ns)             [passed]
    runtime  21.989s  ...  22.446s
nvme/015 (unit test for NVMe flush for file backed ns)       [passed]
    runtime  19.330s  ...  18.614s
nvme/016 (create/delete many NVMeOF block device-backed ns and test discovery) [passed]
    runtime  16.634s  ...  16.945s
nvme/017 (create/delete many file-ns and test discovery)     [passed]
    runtime  16.120s  ...  17.179s
nvme/018 (unit test NVMe-oF out of range access on a file backend) [passed]
    runtime  1.665s  ...  1.676s
nvme/019 (test NVMe DSM Discard command on NVMeOF block-device ns) [passed]
    runtime  1.692s  ...  1.701s
nvme/020 (test NVMe DSM Discard command on NVMeOF file-backed ns) [passed]
    runtime  1.655s  ...  1.662s
nvme/021 (test NVMe list command on NVMeOF file-backed ns)   [passed]
    runtime  1.648s  ...  1.666s
nvme/022 (test NVMe reset command on NVMeOF file-backed ns)  [passed]
    runtime  2.086s  ...  2.099s
nvme/023 (test NVMe smart-log command on NVMeOF block-device ns) [passed]
    runtime  1.683s  ...  1.699s
nvme/024 (test NVMe smart-log command on NVMeOF file-backed ns) [passed]
    runtime  1.653s  ...  1.659s
nvme/025 (test NVMe effects-log command on NVMeOF file-backed ns) [passed]
    runtime  1.653s  ...  1.649s
nvme/026 (test NVMe ns-descs command on NVMeOF file-backed ns) [passed]
    runtime  1.663s  ...  1.658s
nvme/027 (test NVMe ns-rescan command on NVMeOF file-backed ns) [passed]
    runtime  1.661s  ...  1.665s
nvme/028 (test NVMe list-subsys command on NVMeOF file-backed ns) [passed]
    runtime  1.659s  ...  1.663s
nvme/029 (test userspace IO via nvme-cli read/write interface) [passed]
    runtime  2.009s  ...  2.025s
nvme/030 (ensure the discovery generation counter is updated appropriately) [passed]
    runtime  0.316s  ...  0.317s
nvme/031 (test deletion of NVMeOF controllers immediately after setup) [passed]
    runtime  5.608s  ...  5.559s
nvme/038 (test deletion of NVMeOF subsystem without enabling) [passed]
    runtime  0.045s  ...  0.046s

-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Tue Jan 12 16:14:07 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Tue, 12 Jan 2021 13:14:07 -0800
Subject: [V3 1/4] nvmet: set right status on error in id-ns handler
In-Reply-To: <20210112211410.24742-1-chaitanya.kulkarni@wdc.com>
References: <20210112211410.24742-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210112211410.24742-2-chaitanya.kulkarni@wdc.com>

The function nvmet_execute_identify_ns() does't set the status
if call to nvmet_find_namespace() fails. In that case we set the
status of the request to the value return by the nvmet_copy_sgl().

Set the status to NVME_SC_INVALID_NS and adjust the code such that
request will have the right status on nvmet_find_namespace() failure.

Without this patch :-
NVME Identify Namespace 3:
nsze    : 0
ncap    : 0
nuse    : 0
nsfeat  : 0
nlbaf   : 0
flbas   : 0
mc      : 0
dpc     : 0
dps     : 0
nmic    : 0
rescap  : 0
fpi     : 0
dlfeat  : 0
nawun   : 0
nawupf  : 0
nacwu   : 0
nabsn   : 0
nabo    : 0
nabspf  : 0
noiob   : 0
nvmcap  : 0
mssrl   : 0
mcl     : 0
msrc    : 0
nsattr	: 0
nvmsetid: 0
anagrpid: 0
endgid  : 0
nguid   : 00000000000000000000000000000000
eui64   : 0000000000000000
lbaf  0 : ms:0   lbads:0  rp:0 (in use)

With this patch-series :-
# gitlog -4
feb3b88b501e (HEAD -> nvme-5.11) nvmet: remove extra variable in identify ns
6302aa67210a nvmet: remove extra variable in id-desclist
ed57951da453 nvmet: remove extra variable in smart log nsid
be384b8c24dc nvmet: set right status on error in id-ns handler

NVMe status: INVALID_NS: The namespace or the format of that namespace is invalid(0xb)

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/target/admin-cmd.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index 8d90235e4fcc..9bf1fd6933cc 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -487,8 +487,10 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req)
 
 	/* return an all zeroed buffer if we can't find an active namespace */
 	ns = nvmet_find_namespace(ctrl, req->cmd->identify.nsid);
-	if (!ns)
+	if (!ns) {
+		status = NVME_SC_INVALID_NS;
 		goto done;
+	}
 
 	nvmet_ns_revalidate(ns);
 
@@ -541,7 +543,9 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req)
 		id->nsattr |= (1 << 0);
 	nvmet_put_namespace(ns);
 done:
-	status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id));
+	if (nvmet_copy_to_sgl(req, 0, id, sizeof(*id)) && !status)
+		status = NVME_SC_SGL_INVALID_DATA | NVME_SC_DNR;
+
 	kfree(id);
 out:
 	nvmet_req_complete(req, status);
-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Tue Jan 12 16:14:08 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Tue, 12 Jan 2021 13:14:08 -0800
Subject: [V3 2/4] nvmet: remove extra variable in smart log nsid
In-Reply-To: <20210112211410.24742-1-chaitanya.kulkarni@wdc.com>
References: <20210112211410.24742-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210112211410.24742-3-chaitanya.kulkarni@wdc.com>

We remove the extra local variable struct nvmet_ns in
nvmet_get_smart_log_nsid() since req already has ns member that can be
reused, this also eliminates the explicit call to nvmet_put_namespace()
which is already present in the request completion path.

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/target/admin-cmd.c | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index 9bf1fd6933cc..d6713139708a 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -74,11 +74,11 @@ static void nvmet_execute_get_log_page_error(struct nvmet_req *req)
 static u16 nvmet_get_smart_log_nsid(struct nvmet_req *req,
 		struct nvme_smart_log *slog)
 {
-	struct nvmet_ns *ns;
 	u64 host_reads, host_writes, data_units_read, data_units_written;
 
-	ns = nvmet_find_namespace(req->sq->ctrl, req->cmd->get_log_page.nsid);
-	if (!ns) {
+	req->ns = nvmet_find_namespace(req->sq->ctrl,
+				       req->cmd->get_log_page.nsid);
+	if (!req->ns) {
 		pr_err("Could not find namespace id : %d\n",
 				le32_to_cpu(req->cmd->get_log_page.nsid));
 		req->error_loc = offsetof(struct nvme_rw_command, nsid);
@@ -86,23 +86,21 @@ static u16 nvmet_get_smart_log_nsid(struct nvmet_req *req,
 	}
 
 	/* we don't have the right data for file backed ns */
-	if (!ns->bdev)
+	if (!req->ns->bdev)
 		goto out;
 
-	host_reads = part_stat_read(ns->bdev, ios[READ]);
+	host_reads = part_stat_read(req->ns->bdev, ios[READ]);
 	data_units_read =
-		DIV_ROUND_UP(part_stat_read(ns->bdev, sectors[READ]), 1000);
-	host_writes = part_stat_read(ns->bdev, ios[WRITE]);
+		DIV_ROUND_UP(part_stat_read(req->ns->bdev, sectors[READ]), 1000);
+	host_writes = part_stat_read(req->ns->bdev, ios[WRITE]);
 	data_units_written =
-		DIV_ROUND_UP(part_stat_read(ns->bdev, sectors[WRITE]), 1000);
+		DIV_ROUND_UP(part_stat_read(req->ns->bdev, sectors[WRITE]), 1000);
 
 	put_unaligned_le64(host_reads, &slog->host_reads[0]);
 	put_unaligned_le64(data_units_read, &slog->data_units_read[0]);
 	put_unaligned_le64(host_writes, &slog->host_writes[0]);
 	put_unaligned_le64(data_units_written, &slog->data_units_written[0]);
 out:
-	nvmet_put_namespace(ns);
-
 	return NVME_SC_SUCCESS;
 }
 
-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Tue Jan 12 16:14:09 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Tue, 12 Jan 2021 13:14:09 -0800
Subject: [V3 3/4] nvmet: remove extra variable in id-desclist
In-Reply-To: <20210112211410.24742-1-chaitanya.kulkarni@wdc.com>
References: <20210112211410.24742-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210112211410.24742-4-chaitanya.kulkarni@wdc.com>

We remove the extra local variable struct nvmet_ns in
nvmet_execute_identify_desclist() since req already has ns member that
can be reused, this also eliminates the explicit call to
nvmet_put_namespace() which is already present in the request
completion path.

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/target/admin-cmd.c | 20 +++++++++-----------
 1 file changed, 9 insertions(+), 11 deletions(-)

diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index d6713139708a..5a75676da259 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -605,37 +605,35 @@ static u16 nvmet_copy_ns_identifier(struct nvmet_req *req, u8 type, u8 len,
 
 static void nvmet_execute_identify_desclist(struct nvmet_req *req)
 {
-	struct nvmet_ns *ns;
 	u16 status = 0;
 	off_t off = 0;
 
-	ns = nvmet_find_namespace(req->sq->ctrl, req->cmd->identify.nsid);
-	if (!ns) {
+	req->ns = nvmet_find_namespace(req->sq->ctrl, req->cmd->identify.nsid);
+	if (!req->ns) {
 		req->error_loc = offsetof(struct nvme_identify, nsid);
 		status = NVME_SC_INVALID_NS | NVME_SC_DNR;
 		goto out;
 	}
 
-	if (memchr_inv(&ns->uuid, 0, sizeof(ns->uuid))) {
+	if (memchr_inv(&req->ns->uuid, 0, sizeof(req->ns->uuid))) {
 		status = nvmet_copy_ns_identifier(req, NVME_NIDT_UUID,
 						  NVME_NIDT_UUID_LEN,
-						  &ns->uuid, &off);
+						  &req->ns->uuid, &off);
 		if (status)
-			goto out_put_ns;
+			goto out;
 	}
-	if (memchr_inv(ns->nguid, 0, sizeof(ns->nguid))) {
+	if (memchr_inv(req->ns->nguid, 0, sizeof(req->ns->nguid))) {
 		status = nvmet_copy_ns_identifier(req, NVME_NIDT_NGUID,
 						  NVME_NIDT_NGUID_LEN,
-						  &ns->nguid, &off);
+						  &req->ns->nguid, &off);
 		if (status)
-			goto out_put_ns;
+			goto out;
 	}
 
 	if (sg_zero_buffer(req->sg, req->sg_cnt, NVME_IDENTIFY_DATA_SIZE - off,
 			off) != NVME_IDENTIFY_DATA_SIZE - off)
 		status = NVME_SC_INTERNAL | NVME_SC_DNR;
-out_put_ns:
-	nvmet_put_namespace(ns);
+
 out:
 	nvmet_req_complete(req, status);
 }
-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Tue Jan 12 16:14:10 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Tue, 12 Jan 2021 13:14:10 -0800
Subject: [V3 4/4] nvmet: remove extra variable in identify ns
In-Reply-To: <20210112211410.24742-1-chaitanya.kulkarni@wdc.com>
References: <20210112211410.24742-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210112211410.24742-5-chaitanya.kulkarni@wdc.com>

We remove the extra local variable struct nvmet_ns in
nvmet_execute_identify_ns() since req already has ns member that can be
reused, this also eliminates the explicit call to nvmet_put_namespace()
which is already present in the request completion path.

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/target/admin-cmd.c | 30 ++++++++++++++----------------
 1 file changed, 14 insertions(+), 16 deletions(-)

diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index 5a75676da259..1952ff28f95c 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -467,7 +467,6 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
 static void nvmet_execute_identify_ns(struct nvmet_req *req)
 {
 	struct nvmet_ctrl *ctrl = req->sq->ctrl;
-	struct nvmet_ns *ns;
 	struct nvme_id_ns *id;
 	u16 status = 0;
 
@@ -484,20 +483,20 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req)
 	}
 
 	/* return an all zeroed buffer if we can't find an active namespace */
-	ns = nvmet_find_namespace(ctrl, req->cmd->identify.nsid);
-	if (!ns) {
+	req->ns = nvmet_find_namespace(ctrl, req->cmd->identify.nsid);
+	if (!req->ns) {
 		status = NVME_SC_INVALID_NS;
 		goto done;
 	}
 
-	nvmet_ns_revalidate(ns);
+	nvmet_ns_revalidate(req->ns);
 
 	/*
 	 * nuse = ncap = nsze isn't always true, but we have no way to find
 	 * that out from the underlying device.
 	 */
-	id->ncap = id->nsze = cpu_to_le64(ns->size >> ns->blksize_shift);
-	switch (req->port->ana_state[ns->anagrpid]) {
+	id->ncap = id->nsze = cpu_to_le64(req->ns->size >> req->ns->blksize_shift);
+	switch (req->port->ana_state[req->ns->anagrpid]) {
 	case NVME_ANA_INACCESSIBLE:
 	case NVME_ANA_PERSISTENT_LOSS:
 		break;
@@ -506,8 +505,8 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req)
 		break;
         }
 
-	if (ns->bdev)
-		nvmet_bdev_set_limits(ns->bdev, id);
+	if (req->ns->bdev)
+		nvmet_bdev_set_limits(req->ns->bdev, id);
 
 	/*
 	 * We just provide a single LBA format that matches what the
@@ -521,25 +520,24 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req)
 	 * controllers, but also with any other user of the block device.
 	 */
 	id->nmic = (1 << 0);
-	id->anagrpid = cpu_to_le32(ns->anagrpid);
+	id->anagrpid = cpu_to_le32(req->ns->anagrpid);
 
-	memcpy(&id->nguid, &ns->nguid, sizeof(id->nguid));
+	memcpy(&id->nguid, &req->ns->nguid, sizeof(id->nguid));
 
-	id->lbaf[0].ds = ns->blksize_shift;
+	id->lbaf[0].ds = req->ns->blksize_shift;
 
-	if (ctrl->pi_support && nvmet_ns_has_pi(ns)) {
+	if (ctrl->pi_support && nvmet_ns_has_pi(req->ns)) {
 		id->dpc = NVME_NS_DPC_PI_FIRST | NVME_NS_DPC_PI_LAST |
 			  NVME_NS_DPC_PI_TYPE1 | NVME_NS_DPC_PI_TYPE2 |
 			  NVME_NS_DPC_PI_TYPE3;
 		id->mc = NVME_MC_EXTENDED_LBA;
-		id->dps = ns->pi_type;
+		id->dps = req->ns->pi_type;
 		id->flbas = NVME_NS_FLBAS_META_EXT;
-		id->lbaf[0].ms = cpu_to_le16(ns->metadata_size);
+		id->lbaf[0].ms = cpu_to_le16(req->ns->metadata_size);
 	}
 
-	if (ns->readonly)
+	if (req->ns->readonly)
 		id->nsattr |= (1 << 0);
-	nvmet_put_namespace(ns);
 done:
 	if (nvmet_copy_to_sgl(req, 0, id, sizeof(*id)) && !status)
 		status = NVME_SC_SGL_INVALID_DATA | NVME_SC_DNR;
-- 
2.22.1



From lkp at intel.com  Tue Jan 12 16:35:31 2021
From: lkp at intel.com (kernel test robot)
Date: Wed, 13 Jan 2021 05:35:31 +0800
Subject: [linux-nvme:nvme-5.11] BUILD SUCCESS
 1f22a063446758d58d5ca577101736b16cbb9280
Message-ID: <5ffe1623.jAsyb0zoFEhUIQsV%lkp@intel.com>

tree/branch: git://git.infradead.org/nvme.git  nvme-5.11
branch HEAD: 1f22a063446758d58d5ca577101736b16cbb9280  nvme: support command retry delay for admin command

elapsed time: 783m

configs tested: 205
configs skipped: 2

The following configs have been built successfully.
More configs may be tested in the coming days.

gcc tested configs:
arm64                            allyesconfig
arm64                               defconfig
arm                                 defconfig
arm                              allyesconfig
arm                              allmodconfig
sh                           se7206_defconfig
sh                               allmodconfig
um                            kunit_defconfig
powerpc                     akebono_defconfig
powerpc                  mpc866_ads_defconfig
mips                         db1xxx_defconfig
mips                           rs90_defconfig
powerpc                mpc7448_hpc2_defconfig
xtensa                  cadence_csp_defconfig
h8300                       h8s-sim_defconfig
mips                      pic32mzda_defconfig
powerpc                  storcenter_defconfig
arm                        neponset_defconfig
arm                          pxa910_defconfig
powerpc                 mpc85xx_cds_defconfig
arm                    vt8500_v6_v7_defconfig
powerpc                   motionpro_defconfig
c6x                        evmc6678_defconfig
m68k                       m5275evb_defconfig
h8300                               defconfig
arm                         shannon_defconfig
sparc64                             defconfig
arm                            xcep_defconfig
arm                            hisi_defconfig
powerpc                     tqm8548_defconfig
mips                           jazz_defconfig
powerpc                      cm5200_defconfig
arm                          iop32x_defconfig
powerpc                 mpc8540_ads_defconfig
powerpc                     ep8248e_defconfig
mips                    maltaup_xpa_defconfig
arm                          collie_defconfig
arc                     nsimosci_hs_defconfig
arm                         cm_x300_defconfig
m68k                       m5475evb_defconfig
ia64                          tiger_defconfig
mips                      loongson3_defconfig
m68k                          amiga_defconfig
mips                        qi_lb60_defconfig
ia64                         bigsur_defconfig
powerpc                 mpc836x_mds_defconfig
sh                           se7780_defconfig
sh                          sdk7786_defconfig
arm                         mv78xx0_defconfig
arm                          tango4_defconfig
powerpc                       ebony_defconfig
arm                            lart_defconfig
arm                         lubbock_defconfig
arm                     am200epdkit_defconfig
mips                        bcm47xx_defconfig
ia64                      gensparse_defconfig
arm                          moxart_defconfig
powerpc                      arches_defconfig
arm                             rpc_defconfig
arc                        nsimosci_defconfig
m68k                          multi_defconfig
h8300                     edosk2674_defconfig
arm                           h5000_defconfig
sh                  sh7785lcr_32bit_defconfig
mips                        bcm63xx_defconfig
mips                         tb0219_defconfig
sh                           se7712_defconfig
m68k                          sun3x_defconfig
powerpc                      ppc6xx_defconfig
mips                  decstation_64_defconfig
arm                         orion5x_defconfig
sh                      rts7751r2d1_defconfig
openrisc                  or1klitex_defconfig
arm                        magician_defconfig
arm                           corgi_defconfig
sh                          r7785rp_defconfig
powerpc                       eiger_defconfig
m68k                            mac_defconfig
arm                       spear13xx_defconfig
sh                                  defconfig
mips                      malta_kvm_defconfig
sh                ecovec24-romimage_defconfig
mips                        maltaup_defconfig
sh                        dreamcast_defconfig
powerpc                      tqm8xx_defconfig
powerpc                     tqm5200_defconfig
c6x                                 defconfig
c6x                              alldefconfig
openrisc                 simple_smp_defconfig
arm                           h3600_defconfig
m68k                         amcore_defconfig
sh                            shmin_defconfig
c6x                        evmc6472_defconfig
sh                              ul2_defconfig
powerpc                    socrates_defconfig
um                           x86_64_defconfig
arm                         palmz72_defconfig
arm                         assabet_defconfig
powerpc                     stx_gp3_defconfig
sh                   rts7751r2dplus_defconfig
sh                           se7722_defconfig
powerpc                 mpc834x_itx_defconfig
csky                             alldefconfig
arm                           omap1_defconfig
mips                         cobalt_defconfig
m68k                       bvme6000_defconfig
arm                        cerfcube_defconfig
sh                             shx3_defconfig
m68k                           sun3_defconfig
sparc64                          alldefconfig
powerpc                     kmeter1_defconfig
xtensa                  nommu_kc705_defconfig
arm                          prima2_defconfig
arm                           stm32_defconfig
arc                           tb10x_defconfig
arc                              alldefconfig
mips                 decstation_r4k_defconfig
powerpc                      bamboo_defconfig
arm                          ixp4xx_defconfig
arm                         hackkit_defconfig
m68k                          atari_defconfig
arm                              zx_defconfig
powerpc                          g5_defconfig
ia64                             allmodconfig
ia64                                defconfig
ia64                             allyesconfig
m68k                             allmodconfig
m68k                                defconfig
m68k                             allyesconfig
nios2                               defconfig
arc                              allyesconfig
nds32                             allnoconfig
c6x                              allyesconfig
nds32                               defconfig
nios2                            allyesconfig
csky                                defconfig
alpha                               defconfig
alpha                            allyesconfig
xtensa                           allyesconfig
h8300                            allyesconfig
arc                                 defconfig
parisc                              defconfig
s390                             allyesconfig
parisc                           allyesconfig
s390                                defconfig
i386                             allyesconfig
sparc                            allyesconfig
sparc                               defconfig
i386                               tinyconfig
i386                                defconfig
mips                             allyesconfig
mips                             allmodconfig
powerpc                          allyesconfig
powerpc                          allmodconfig
powerpc                           allnoconfig
i386                 randconfig-a002-20210112
i386                 randconfig-a005-20210112
i386                 randconfig-a006-20210112
i386                 randconfig-a003-20210112
i386                 randconfig-a001-20210112
i386                 randconfig-a004-20210112
x86_64               randconfig-a015-20210112
x86_64               randconfig-a012-20210112
x86_64               randconfig-a013-20210112
x86_64               randconfig-a016-20210112
x86_64               randconfig-a014-20210112
x86_64               randconfig-a011-20210112
i386                 randconfig-a012-20210112
i386                 randconfig-a011-20210112
i386                 randconfig-a016-20210112
i386                 randconfig-a013-20210112
i386                 randconfig-a015-20210112
i386                 randconfig-a014-20210112
x86_64               randconfig-a004-20210111
x86_64               randconfig-a006-20210111
x86_64               randconfig-a001-20210111
x86_64               randconfig-a003-20210111
x86_64               randconfig-a005-20210111
x86_64               randconfig-a002-20210111
riscv                            allyesconfig
riscv                             allnoconfig
riscv                               defconfig
riscv                            allmodconfig
riscv                    nommu_k210_defconfig
riscv                    nommu_virt_defconfig
riscv                          rv32_defconfig
x86_64                                   rhel
x86_64                           allyesconfig
x86_64                    rhel-7.6-kselftests
x86_64                              defconfig
x86_64                               rhel-8.3
x86_64                      rhel-8.3-kbuiltin
x86_64                                  kexec

clang tested configs:
x86_64               randconfig-a006-20210112
x86_64               randconfig-a004-20210112
x86_64               randconfig-a001-20210112
x86_64               randconfig-a005-20210112
x86_64               randconfig-a003-20210112
x86_64               randconfig-a002-20210112
x86_64               randconfig-a015-20210111
x86_64               randconfig-a012-20210111
x86_64               randconfig-a013-20210111
x86_64               randconfig-a016-20210111
x86_64               randconfig-a014-20210111
x86_64               randconfig-a011-20210111

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all at lists.01.org


From kbusch at kernel.org  Tue Jan 12 16:48:01 2021
From: kbusch at kernel.org (Keith Busch)
Date: Tue, 12 Jan 2021 13:48:01 -0800
Subject: [V3 1/4] nvmet: set right status on error in id-ns handler
In-Reply-To: <20210112211410.24742-2-chaitanya.kulkarni@wdc.com>
References: <20210112211410.24742-1-chaitanya.kulkarni@wdc.com>
 <20210112211410.24742-2-chaitanya.kulkarni@wdc.com>
Message-ID: <20210112214801.GA1505636@dhcp-10-100-145-180.wdc.com>

On Tue, Jan 12, 2021 at 01:14:07PM -0800, Chaitanya Kulkarni wrote:
> @@ -541,7 +543,9 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req)
>  		id->nsattr |= (1 << 0);
>  	nvmet_put_namespace(ns);
>  done:
> -	status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id));
> +	if (nvmet_copy_to_sgl(req, 0, id, sizeof(*id)) && !status)
> +		status = NVME_SC_SGL_INVALID_DATA | NVME_SC_DNR;

If the status is already in error, you don't need to copy out the
blank struct, right? Shouldn't this be like:

	if (!status)
		status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id));


From Chaitanya.Kulkarni at wdc.com  Tue Jan 12 20:20:51 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Wed, 13 Jan 2021 01:20:51 +0000
Subject: [PATCH V9 1/9] block: export bio_add_hw_pages()
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-2-chaitanya.kulkarni@wdc.com>
 <20210112072441.GA24155@lst.de>
Message-ID: <BYAPR04MB4965CA7945266B82A6A8022C86A90@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/11/21 23:24, Christoph Hellwig wrote:
> EXPORT_SYMBOL_GPL, please.
>
Okay.


From Chaitanya.Kulkarni at wdc.com  Tue Jan 12 23:16:51 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Wed, 13 Jan 2021 04:16:51 +0000
Subject: [PATCH V9 3/9] nvmet: add NVM command set identifier support
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-4-chaitanya.kulkarni@wdc.com>
 <20210112072715.GB24155@lst.de>
Message-ID: <BYAPR04MB4965017878A807316A0A1BBA86A90@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/11/21 23:27, Christoph Hellwig wrote:
> The Command Set Identifier has no "NVM" in its name.
>
>
>> +static inline bool nvmet_cc_css_check(u8 cc_css)
>> +{
>> +	switch (cc_css <<= NVME_CC_CSS_SHIFT) {
>> +	case NVME_CC_CSS_NVM:
>> +		return true;
>> +	default:
>> +		return false;
>> +	}
>> +}
> This hunk looks misplaced, it isn't very useful on its own, but
> should go together with the multiple command set support.
>
We advertise the support for command sets supported in
nvmet_init_cap() -> ctrl->cap = (1ULL << 37). This results in
nvme_enable_ctrl() setting the ctrl->ctrl_config -> NVME_CC_CSS_NVM.
In current code in nvmet_start_ctrl() ->  nvmet_cc_css(ctrl->cc) != 0
checks if value is not = 0 but doesn't use the macro used by the host.
Above function does that also makes it helper that we use in the next
patch where cc_css value is != 0 but NVME_CC_CSS_CSI with
ctrl->cap set to 1ULL << 43.

With code flow in [1] above function is needed to make sure css value
matches the value set by the host using the same macro in
nvme_enable_ctrl() NVME_CC_CSS_NVM. Otherwise patch looks incomplete
and adding check for the CSS NVM with CSS_CSI looks mixing up things
to me.

Are you okay with that ?

[1]
nvme_enable_ctrl()
 ctrl->ops->reg_write32(ctrl, NVME_REG_CC, ctrl->ctrl_config)
  nvmf_reg_write32()
   nvmet_parse_fabrics_cmd()
    nvmet_execute_prop_set()
     nvmet_update_ctrl()
      new cc != old cc == true -> nvmet_start_ctrl()
       nvmet_cc_css_check(ctrl->css)
        Check if host has set the for controller config NVME_CC_CSS_NVM
        as we are supporting default CSS_NVM which ctrl needs to set
        irrespective of other CC_CSS values.
      
 




From Chaitanya.Kulkarni at wdc.com  Tue Jan 12 23:57:15 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Wed, 13 Jan 2021 04:57:15 +0000
Subject: [PATCH V9 4/9] nvmet: add ZBD over ZNS backend support
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-5-chaitanya.kulkarni@wdc.com>
 <20210112074805.GA24443@lst.de>
Message-ID: <BYAPR04MB4965CE08B1DE8BC36585991686A90@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/11/21 23:48, Christoph Hellwig wrote:
>> diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
>> index a50b7bcac67a..bdf09d8faa48 100644
>> --- a/drivers/nvme/target/admin-cmd.c
>> +++ b/drivers/nvme/target/admin-cmd.c
>> @@ -191,6 +191,15 @@ static void nvmet_execute_get_log_cmd_effects_ns(struct nvmet_req *req)
>>  		log->iocs[nvme_cmd_dsm]			= cpu_to_le32(1 << 0);
>>  		log->iocs[nvme_cmd_write_zeroes]	= cpu_to_le32(1 << 0);
>>  		break;
>> +	case NVME_CSI_ZNS:
>> +		if (IS_ENABLED(CONFIG_BLK_DEV_ZONED)) {
>> +			u32 *iocs = log->iocs;
>> +
>> +			iocs[nvme_cmd_zone_append]	= cpu_to_le32(1 << 0);
>> +			iocs[nvme_cmd_zone_mgmt_send]	= cpu_to_le32(1 << 0);
>> +			iocs[nvme_cmd_zone_mgmt_recv]	= cpu_to_le32(1 << 0);
>> +		}
>> +		break;
> We need to return errors if the command set is not actually supported.
> I also think splitting this into one helper per command set would
> be nice.
>
Okay.
>> @@ -644,6 +653,17 @@ static void nvmet_execuIt should be te_identify_desclist(struct nvmet_req *req)
>>  	if (status)
>>  		goto out;
>>  
>> +	if (IS_ENABLED(CONFIG_BLK_DEV_ZONED)) {
>> +		u16 nvme_cis_zns = NVME_CSI_ZNS;
>> +
>> +		if (req->ns->csi == NVME_CSI_ZNS)
>> +			status = nvmet_copy_ns_identifier(req, NVME_NIDT_CSI,
>> +							  NVME_NIDT_CSI_LEN,
>> +							  &nvme_cis_zns, &off);
>> +		if (status)
>> +			goto out;
>> +	}
> We need to add the CSI for every namespace, i.e. something like:
>
> 	status = nvmet_copy_ns_identifier(req, NVME_NIDT_CSI, NVME_NIDT_CSI_LEN,
> 					  &req->ns->csi);		
> 	if (status)
> 		goto out;
>
> and this hunk needs to go into the CSI patch.
even better, we can get rid of the local variables...
>>  	if (sg_zero_buffer(req->sg, req->sg_cnt, NVME_IDENTIFY_DATA_SIZE - off,
>>  			off) != NVME_IDENTIFY_DATA_SIZE - off)
>>  		status = NVME_SC_INTERNAL | NVME_SC_DNR;
>> @@ -660,8 +680,16 @@ static void nvmet_execute_identify(struct nvmet_req *req)
>>  	switch (req->cmd->identify.cns) {
>>  	case NVME_ID_CNS_NS:
>>  		return nvmet_execute_identify_ns(req);
>> +	case NVME_ID_CNS_CS_NS:
>> +		if (req->cmd->identify.csi == NVME_CSI_ZNS)
>> +			return nvmet_execute_identify_cns_cs_ns(req);
>> +		break;
>>  	case NVME_ID_CNS_CTRL:
>>  		return nvmet_execute_identify_ctrl(req);
>> +	case NVME_ID_CNS_CS_CTRL:
>> +		if (req->cmd->identify.csi == NVME_CSI_ZNS)
>> +			return nvmet_execute_identify_cns_cs_ctrl(req);
>> +		break;
> How does the CSI get mirrored into the cns field?
>
There is only one cns and one csi value we set from host/zns.c
This is just to reject req if we receive anything else or there is
any change on the host we fail.
>> diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
>> index 672e4009f8d6..17d5da062a5a 100644
>> --- a/drivers/nvme/target/core.c
>> +++ b/drivers/nvme/target/core.c
>> @@ -1107,6 +1107,7 @@ static inline u8 nvmet_cc_iocqes(u32 cc)
>>  static inline bool nvmet_cc_css_check(u8 cc_css)
>>  {
>>  	switch (cc_css <<= NVME_CC_CSS_SHIFT) {
>> +	case NVME_CC_CSS_CSI:
>>  	case NVME_CC_CSS_NVM:
>>  		return true;
>>  	default:
>> @@ -1173,6 +1174,8 @@ static void nvmet_init_cap(struct nvmet_ctrl *ctrl)
>>  {
>>  	/* command sets supported: NVMe command set: */
>>  	ctrl->cap = (1ULL << 37);
>> +	if (IS_ENABLED(CONFIG_BLK_DEV_ZONED))
>> +		ctrl->cap |= (1ULL << 43);
>>  	/* CC.EN timeout in 500msec units: */
>>  	ctrl->cap |= (15ULL << 24);
>>  	/* maximum queue entries supported: */
> This needs to go into a separate patch for multiple command set support.
> We can probably merge the CAP and CC bits with the CSI support, though.
Do you mean previous patch ? but we don't add handlers non-default I/O
command set until this patch..
>> +	if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) && bdev_is_zoned(ns->bdev)) {
> bdev_is_zoned should be probably stubbed out for !CONFIG_BLK_DEV_ZONED
> these days.
Are you saying something like following in the prep patch ?or should
just remove
theIS_ENABLED(CONFIG_BLK_DEV_ZONED)part in above if?

diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 028ccc9bdf8d..124086c1a0ba 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1570,6 +1570,9 @@ static inline bool bdev_is_zoned(struct
block_device *bdev)
 {
        struct request_queue *q = bdev_get_queue(bdev);
 
+       if (!IS_ENABLED(CONFIG_BLK_DEV_ZONED))
+               return false;
+
        if (q)
                return blk_queue_is_zoned(q);
>> +/*
>> + *  ZNS related command implementation and helpers.
>> + */
> Well, that is the description of the whole file, isn't it?  I don't think
> this comment adds much value.
Stupid comment, will remove it.
>> +	/*
>> +	 * For ZBC and ZAC devices, writes into sequential zones must be aligned
>> +	 * to the device physical block size. So use this value as the logical
>> +	 * block size to avoid errors.
>> +	 */
> I do not understand the logic here, given that NVMe does not have
> conventional zones.
>
It should be :-

	/*
	 * For ZBC and ZAC devices, writes into sequential zones must be aligned
	 * to the device physical block size. So use this value as the *physical*
	 * block size to avoid errors.
	 */




From Chaitanya.Kulkarni at wdc.com  Wed Jan 13 00:03:05 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Wed, 13 Jan 2021 05:03:05 +0000
Subject: [PATCH V9 5/9] nvmet: add bio get helper for different backends
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-6-chaitanya.kulkarni@wdc.com>
 <20210112073315.GA24288@lst.de>
Message-ID: <BYAPR04MB4965361DC74566BD26E3DC7B86A90@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/11/21 23:33, Christoph Hellwig wrote:
> I'm not a huge fan of this helper, especially as it sets an end_io
> callback only for the allocated case, which is a weird calling
> convention.
>

The patch has a right documentation and that end_io is needed
for passthru case. To get rid of the weirdness I can remove
passthru case and make itend_io assign to inline and non-inline bio
to make it non-weired.

Since this eliminates exactly identical lines of the code in atleast two
backend which we should try to use the helper in non-wried way.



From Chaitanya.Kulkarni at wdc.com  Wed Jan 13 00:04:49 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Wed, 13 Jan 2021 05:04:49 +0000
Subject: [PATCH V9 6/9] nvmet: add bio init helper for different backends
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-7-chaitanya.kulkarni@wdc.com>
 <20210112073358.GB24288@lst.de>
Message-ID: <BYAPR04MB4965824B7DB93A26C625AAD586A90@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/11/21 23:34, Christoph Hellwig wrote:
> Nothing NVMe specific about this.  The helper also doesn't relaly contain
> any logic either.
>
What is the preferable name ? just bio_init_fields() ?


From Chaitanya.Kulkarni at wdc.com  Wed Jan 13 00:07:16 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Wed, 13 Jan 2021 05:07:16 +0000
Subject: [PATCH V9 8/9] nvmet: add common I/O length check helper
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-9-chaitanya.kulkarni@wdc.com>
 <20210112073503.GC24288@lst.de>
Message-ID: <BYAPR04MB4965136E54EA80910B9ED43986A90@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/11/21 23:35, Christoph Hellwig wrote:
> I can't say I like this helper.  The semantics are a little confusing,
> not helped by the name.
>
Is it because of the name of the helper ? if so can you please suggest a
name.
Because all it has a same code repeated in the three backends and it really
bothers me to see duplicate code, but that just me :P.


From Chaitanya.Kulkarni at wdc.com  Wed Jan 13 00:13:34 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Wed, 13 Jan 2021 05:13:34 +0000
Subject: [PATCH V9 9/9] nvmet: call nvmet_bio_done() for zone append
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-10-chaitanya.kulkarni@wdc.com>
 <20210112073606.GD24288@lst.de>
Message-ID: <BYAPR04MB4965963BCC2BC929CC4B730F86A90@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/11/21 23:36, Christoph Hellwig wrote:
> I don't see much of a need to share such trivial functionality over
> different codebases.
>
Since there is a function which does exactly same thing thwn why we should
open code ? I didn't find a good reason to open code, in fact it made it
easier
to search for nvmet_bio_done() which is logical point.

We can drop this but please consider previous patches as it has a lot of
repetitive code. (will remove the weirdness and add name fixes).



From elad.grupi at dell.com  Wed Jan 13 06:51:52 2021
From: elad.grupi at dell.com (elad.grupi at dell.com)
Date: Wed, 13 Jan 2021 13:51:52 +0200
Subject: [PATCH] nvme-tcp: fix a segmentation fault during io parsing error
Message-ID: <20210113115152.69692-1-elad.grupi@dell.com>

From: Elad Grupi <elad.grupi at dell.com>

    In case there is an io that contains inline data and it goes to
    parsing error flow, command response will free command and iov
    before clearing the data on the socket buffer.
    This will delay the command response until receive flow is completed.

Signed-off-by: Elad Grupi <elad.grupi at dell.com>
---
 drivers/nvme/target/tcp.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
index d535080b781f..dea94da4c9ba 100644
--- a/drivers/nvme/target/tcp.c
+++ b/drivers/nvme/target/tcp.c
@@ -146,6 +146,7 @@ static struct workqueue_struct *nvmet_tcp_wq;
 static struct nvmet_fabrics_ops nvmet_tcp_ops;
 static void nvmet_tcp_free_cmd(struct nvmet_tcp_cmd *c);
 static void nvmet_tcp_finish_cmd(struct nvmet_tcp_cmd *cmd);
+static void nvmet_tcp_queue_response(struct nvmet_req *req);
 
 static inline u16 nvmet_tcp_cmd_tag(struct nvmet_tcp_queue *queue,
 		struct nvmet_tcp_cmd *cmd)
@@ -476,7 +477,11 @@ static struct nvmet_tcp_cmd *nvmet_tcp_fetch_cmd(struct nvmet_tcp_queue *queue)
 		nvmet_setup_c2h_data_pdu(queue->snd_cmd);
 	else if (nvmet_tcp_need_data_in(queue->snd_cmd))
 		nvmet_setup_r2t_pdu(queue->snd_cmd);
-	else
+	else if (nvmet_tcp_has_data_in(queue->snd_cmd) &&
+			nvmet_tcp_has_inline_data(queue->snd_cmd)) {
+		nvmet_tcp_queue_response(&queue->snd_cmd->req);
+		queue->snd_cmd = NULL;
+	} else
 		nvmet_setup_response_pdu(queue->snd_cmd);
 
 	return queue->snd_cmd;
-- 
2.16.5



From minwoo.im.dev at gmail.com  Wed Jan 13 09:34:31 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Wed, 13 Jan 2021 23:34:31 +0900
Subject: [PATCH V5 0/1] block: fix I/O errors in BLKRRPART
Message-ID: <20210113143432.426-1-minwoo.im.dev@gmail.com>

Hello,

  This patch fixes I/O errors during BLKRRPART ioctl() behavior right
after format operation that changed logical block size of the block
device with a same file descriptor opened.

Testcase:

  The following testcase is a case of NVMe namespace with the following
conditions:

  - Current LBA format is lbaf=0 (512 bytes logical block size)
  - LBA Format(lbaf=1) has 4096 bytes logical block size

  # Format block device logical block size 512B to 4096B                                                                                                                                                                                                                                                                                                                                       
  nvme format /dev/nvme0n1 --lbaf=1 --force

  This will cause I/O errors because BLKRRPART ioctl() happened right after
the format command with same file descriptor opened in application
(e.g., nvme-cli) like:

  fd = open("/dev/nvme0n1", O_RDONLY);

  nvme_format(fd, ...);
  if (ioctl(fd, BLKRRPART) < 0)
        ...

Errors:

  We can see the Read command with Number of LBA(NLB) 0xffff(65535) which
was under-flowed because BLKRRPART operation requested request size based
on i_blkbits of the block device which is 9 via buffer_head.

  [dmesg-snip]
    [   10.771740] blk_update_request: operation not supported error, dev nvme0n1, sector 0 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 0
    [   10.780262] Buffer I/O error on dev nvme0n1, logical block 0, async page read

  [event-snip]
    kworker/0:1H-56      [000] ....   913.456922: nvme_setup_cmd: nvme0: disk=nvme0n1, qid=1, cmdid=216, nsid=1, flags=0x0, meta=0x0, cmd=(nvme_cmd_read slba=0, len=65535, ctrl=0x0, dsmgmt=0, reftag=0)
     ksoftirqd/0-9       [000] .Ns.   916.566351: nvme_complete_rq: nvme0: disk=nvme0n1, qid=1, cmdid=216, res=0x0, retries=0, flags=0x0, status=0x4002

  The patch below fixes the I/O errors by rejecting I/O requests from the
block layer with setting a flag to request_queue until the file descriptor
re-opened to be updated by __blkdev_get().  This is based on the previous
discussion [1].

Since V4:
  - Rebased on block-5.11.
  - Added Reviewed-by Tag from Christoph.

Since V3(RFC):
  - Move flag from gendisk to request_queue for future clean-ups.
    (Christoph, [3])

Since V2(RFC):
  - Cover letter with testcase and error logs attached. Removed un-related
    changes: empty line. (Chaitanya, [2])
  - Put blkdev with blkdev_put_no_open().

Since V1(RFC):
  - Updated patch to reject I/O rather than updating i_blkbits of the
    block device's inode directly from driver. (Christoph, [1])

[1] https://lore.kernel.org/linux-nvme/20201223183143.GB13354 at localhost.localdomain/T/#t
[2] https://lore.kernel.org/linux-nvme/20201230140504.GB7917 at localhost.localdomain/T/#t
[3] https://lore.kernel.org/linux-block/20210105101202.GA9970 at localhost.localdomain/T/#u

Thanks,

Minwoo Im (1):
  block: reject I/O for same fd if block size changed

 block/blk-settings.c    |  3 +++
 block/partitions/core.c | 12 ++++++++++++
 fs/block_dev.c          |  8 ++++++++
 include/linux/blkdev.h  |  1 +
 4 files changed, 24 insertions(+)

-- 
2.17.1



From minwoo.im.dev at gmail.com  Wed Jan 13 09:34:32 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Wed, 13 Jan 2021 23:34:32 +0900
Subject: [PATCH V5 1/1] block: reject I/O for same fd if block size changed
In-Reply-To: <20210113143432.426-1-minwoo.im.dev@gmail.com>
References: <20210113143432.426-1-minwoo.im.dev@gmail.com>
Message-ID: <20210113143432.426-2-minwoo.im.dev@gmail.com>

This patch fixes I/O errors during BLKRRPART ioctl() behavior right
after format operation that changed logical block size of the block
device with a same file descriptor opened.

This issue can be easily reproduced with a single format command in case
of NVMe (logical block size 512B to 4096B).

	nvme format /dev/nvme0n1 --lbaf=1 --force

This is because the application, nvme-cli format subcommand issues an
admin command followed by BLKRRPART ioctl to re-read partition
information without closing the file descriptor.  If file descriptor
stays opened, __blkdev_get() will not be invoked at all even logical
block size has been changed.

It will cause I/O errors with invalid Read operations during the
BLKRRPART ioctl due to i_blkbits mismatch. The invalid operations in
BLKRRPART happens with under-flowed Number of LBA(NLB) values
0xffff(65535) because i_blkbits is still set to 9 even the logical block
size has been updated to 4096.  The BLKRRPART will lead buffer_head to
hold 512B data which is less than the logical lock size of the block
device.

The root cause, which is because i_blkbits of inode of the block device
is not updated, can be solved easily by re-opening file descriptor
again from application.  But, that's just for application's business
and kernel should reject invalid Read operations during the BLKRRPART
ioctl.

This patch rejects I/O from the path of add_partitions() to avoid
issuing invalid Read operations to device.  It sets a flag to
request_queue in blk_queue_logical_block_size to minimize caller-side
updates.

Signed-off-by: Minwoo Im <minwoo.im.dev at gmail.com>
Reviewed-by: Christoph Hellwig <hch at lst.de>
---
 block/blk-settings.c    |  3 +++
 block/partitions/core.c | 12 ++++++++++++
 fs/block_dev.c          |  8 ++++++++
 include/linux/blkdev.h  |  1 +
 4 files changed, 24 insertions(+)

diff --git a/block/blk-settings.c b/block/blk-settings.c
index 43990b1d148b..48a6fc7bb5f5 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -329,6 +329,9 @@ void blk_queue_logical_block_size(struct request_queue *q, unsigned int size)
 {
 	struct queue_limits *limits = &q->limits;
 
+	if (limits->logical_block_size != size)
+		blk_queue_flag_set(QUEUE_FLAG_LBSZ_CHANGED, q);
+
 	limits->logical_block_size = size;
 
 	if (limits->physical_block_size < size)
diff --git a/block/partitions/core.c b/block/partitions/core.c
index e7d776db803b..6f175ea18ff3 100644
--- a/block/partitions/core.c
+++ b/block/partitions/core.c
@@ -612,12 +612,24 @@ static bool blk_add_partition(struct gendisk *disk, struct block_device *bdev,
 
 int blk_add_partitions(struct gendisk *disk, struct block_device *bdev)
 {
+	struct request_queue *q = bdev_get_queue(bdev);
 	struct parsed_partitions *state;
 	int ret = -EAGAIN, p, highest;
 
 	if (!disk_part_scan_enabled(disk))
 		return 0;
 
+	/*
+	 * Reject to check partition information if block size has been changed
+	 * in the runtime.  If block size of a block device has been changed,
+	 * the file descriptor should be opened agian to update the blkbits.
+	 */
+	if (test_bit(QUEUE_FLAG_LBSZ_CHANGED, &q->queue_flags)) {
+		pr_warn("%s: rejecting checking partition. fd should be opened again.\n",
+				disk->disk_name);
+		return -EBADFD;
+	}
+
 	state = check_partition(disk, bdev);
 	if (!state)
 		return 0;
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 3b8963e228a1..db5b0b75f0be 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -130,7 +130,15 @@ EXPORT_SYMBOL(truncate_bdev_range);
 
 static void set_init_blocksize(struct block_device *bdev)
 {
+	struct request_queue *q = bdev_get_queue(bdev);
+
 	bdev->bd_inode->i_blkbits = blksize_bits(bdev_logical_block_size(bdev));
+
+	/*
+	 * Allow I/O commands for this block device.  We can say that this
+	 * block device has proper blkbits updated.
+	 */
+	blk_queue_flag_clear(QUEUE_FLAG_LBSZ_CHANGED, q);
 }
 
 int set_blocksize(struct block_device *bdev, int size)
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 070de09425ad..6d0542434be6 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -625,6 +625,7 @@ struct request_queue {
 #define QUEUE_FLAG_RQ_ALLOC_TIME 27	/* record rq->alloc_time_ns */
 #define QUEUE_FLAG_HCTX_ACTIVE	28	/* at least one blk-mq hctx is active */
 #define QUEUE_FLAG_NOWAIT       29	/* device supports NOWAIT */
+#define QUEUE_FLAG_LBSZ_CHANGED	30	/* logical block size changed */
 
 #define QUEUE_FLAG_MQ_DEFAULT	((1 << QUEUE_FLAG_IO_STAT) |		\
 				 (1 << QUEUE_FLAG_SAME_COMP) |		\
-- 
2.17.1



From minwoo.im.dev at gmail.com  Wed Jan 13 09:35:36 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Wed, 13 Jan 2021 23:35:36 +0900
Subject: [PATCH V2 0/2] nvme: fixes for command retry
Message-ID: <20210113143538.554-1-minwoo.im.dev@gmail.com>

Hello,

This patch series is V2 for Advanced Command Retry Enable(ACRE) feature.

The first patch checks all CRDT(Command Retry Delay Time) [0..2] to
figure out whether CRDT is configured or not.

The other patch has been updated to take internal flag in the controller
instance instead of the module parameter which has been posted in the
previous series [1].  This is based on the review by Chao: Thanks Chao!

Please review.

Thanks,

Since V1:
  - The first patch has been applied (Christoph).  Removed from this
    series.
  - Update the last patch to take acre flag from the controller
    instance instead of module parameter by updating
    nvme_decide_disposition().  (Chao)

[1] https://lore.kernel.org/linux-nvme/20210108144659.7126-1-minwoo.im.dev at gmail.com/T/#t

Minwoo Im (2):
  nvme: check all retry delay times in Identify Controller
  nvme: retry commands based on ACRE result

 drivers/nvme/host/core.c | 18 +++++++++++++++---
 drivers/nvme/host/nvme.h |  1 +
 2 files changed, 16 insertions(+), 3 deletions(-)

-- 
2.17.1



From minwoo.im.dev at gmail.com  Wed Jan 13 09:35:37 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Wed, 13 Jan 2021 23:35:37 +0900
Subject: [PATCH V2 1/2] nvme: check all retry delay times in Identify
 Controller
In-Reply-To: <20210113143538.554-1-minwoo.im.dev@gmail.com>
References: <20210113143538.554-1-minwoo.im.dev@gmail.com>
Message-ID: <20210113143538.554-2-minwoo.im.dev@gmail.com>

If none of Command Retry Delay Time(CRDT)s are set, then we can simply
skip to configure Advanced Command Retry Enable(ACRE).

CRDT selection will be made in Completion Queue Entry that controller
has responsibility to decide.

This patch checks all CRDT[0, 1, and 2] in Identify Controller data
structrure instead of checking the first one: CRDT[0] for cases that:

	- CRDT[0] == 0, but CRDT[1 or 2] != 0

Signed-off-by: Minwoo Im <minwoo.im.dev at gmail.com>
---
 drivers/nvme/host/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index fff49e544fdf..a8cee380b3c0 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -2499,7 +2499,7 @@ static int nvme_configure_acre(struct nvme_ctrl *ctrl)
 	int ret;
 
 	/* Don't bother enabling the feature if retry delay is not reported */
-	if (!ctrl->crdt[0])
+	if (!ctrl->crdt[0] && !ctrl->crdt[1] && !ctrl->crdt[2])
 		return 0;
 
 	host = kzalloc(sizeof(*host), GFP_KERNEL);
-- 
2.17.1



From minwoo.im.dev at gmail.com  Wed Jan 13 09:35:38 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Wed, 13 Jan 2021 23:35:38 +0900
Subject: [PATCH V2 2/2] nvme: retry commands based on ACRE result
In-Reply-To: <20210113143538.554-1-minwoo.im.dev@gmail.com>
References: <20210113143538.554-1-minwoo.im.dev@gmail.com>
Message-ID: <20210113143538.554-3-minwoo.im.dev@gmail.com>

Introduce acre flag for Advanced Command Retry Enable to controller
instance to decide whether to retry or not in error cases.  This flag is
set if Set Features for Host Behavior Support with ACRE bit set is
successfully done during reset_work.

This patch also fixes nvme_decide_disposition() because all the nvme
requests are initialized with REQ_FAILFAST_DRIVER to req->cmd_flags so
that blk_noretry_request(req) is always true.  Check ctrl->acre first
and if it's not host path error, then it will be retried.

Cc: Chao Leng <lengchao at huawei.com>
Signed-off-by: Minwoo Im <minwoo.im.dev at gmail.com>
---
 drivers/nvme/host/core.c | 16 ++++++++++++++--
 drivers/nvme/host/nvme.h |  1 +
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index a8cee380b3c0..391bb2d08d0f 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -303,8 +303,7 @@ static inline enum nvme_disposition nvme_decide_disposition(struct request *req)
 	if (likely(nvme_req(req)->status == 0))
 		return COMPLETE;
 
-	if (blk_noretry_request(req) ||
-	    (nvme_req(req)->status & NVME_SC_DNR) ||
+	if ((nvme_req(req)->status & NVME_SC_DNR) ||
 	    nvme_req(req)->retries >= nvme_max_retries)
 		return COMPLETE;
 
@@ -317,6 +316,13 @@ static inline enum nvme_disposition nvme_decide_disposition(struct request *req)
 			return COMPLETE;
 	}
 
+	if (nvme_req(req)->ctrl->acre) {
+		if (!nvme_is_path_error(nvme_req(req)->status) &&
+				!blk_queue_dying(req->q))
+			return RETRY;
+	} else if (blk_noretry_request(req))
+		return COMPLETE;
+
 	return RETRY;
 }
 
@@ -2498,6 +2504,8 @@ static int nvme_configure_acre(struct nvme_ctrl *ctrl)
 	struct nvme_feat_host_behavior *host;
 	int ret;
 
+	ctrl->acre = false;
+
 	/* Don't bother enabling the feature if retry delay is not reported */
 	if (!ctrl->crdt[0] && !ctrl->crdt[1] && !ctrl->crdt[2])
 		return 0;
@@ -2509,6 +2517,10 @@ static int nvme_configure_acre(struct nvme_ctrl *ctrl)
 	host->acre = NVME_ENABLE_ACRE;
 	ret = nvme_set_features(ctrl, NVME_FEAT_HOST_BEHAVIOR, 0,
 				host, sizeof(*host), NULL);
+
+	if (!ret)
+		ctrl->acre = true;
+
 	kfree(host);
 	return ret;
 }
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 88a6b97247f5..db8b45e8ffde 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -270,6 +270,7 @@ struct nvme_ctrl {
 #ifdef CONFIG_BLK_DEV_ZONED
 	u32 max_zone_append;
 #endif
+	bool acre;
 	u16 crdt[3];
 	u16 oncs;
 	u16 oacs;
-- 
2.17.1



From minwoo.im.dev at gmail.com  Wed Jan 13 09:36:27 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Wed, 13 Jan 2021 23:36:27 +0900
Subject: [PATCH] nvme: refactor ns->ctrl by request
Message-ID: <20210113143627.787-1-minwoo.im.dev@gmail.com>

Just for current code in nvme_cleanup_cmd(), we don't have to get
namespace instance, but we need controller instance.

Controller instance can be retrieved by namespace instance, but it can
be directly accessed by nvme_request instance from request.

	ctrl = nvme_req(req)->ctrl;

We don't have to go around namespace instance from request instance
through gendisk.

Signed-off-by: Minwoo Im <minwoo.im.dev at gmail.com>
---
 drivers/nvme/host/core.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index fff49e544fdf..c8da271a77d7 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -841,11 +841,11 @@ static inline blk_status_t nvme_setup_rw(struct nvme_ns *ns,
 void nvme_cleanup_cmd(struct request *req)
 {
 	if (req->rq_flags & RQF_SPECIAL_PAYLOAD) {
-		struct nvme_ns *ns = req->rq_disk->private_data;
+		struct nvme_ctrl *ctrl = nvme_req(req)->ctrl;
 		struct page *page = req->special_vec.bv_page;
 
-		if (page == ns->ctrl->discard_page)
-			clear_bit_unlock(0, &ns->ctrl->discard_page_busy);
+		if (page == ctrl->discard_page)
+			clear_bit_unlock(0, &ctrl->discard_page_busy);
 		else
 			kfree(page_address(page) + req->special_vec.bv_offset);
 	}
-- 
2.17.1



From fengli at smartx.com  Wed Jan 13 11:06:21 2021
From: fengli at smartx.com (Li Feng)
Date: Thu, 14 Jan 2021 00:06:21 +0800
Subject: [PATCH] nvme: reject the ns when the block size is smaller than a
 sector
Message-ID: <20210113160621.98615-1-fengli@smartx.com>

The nvme spec(1.4a, figure 248) says:
"A value smaller than 9 (i.e., 512 bytes) is not supported."

Signed-off-by: Li Feng <fengli at smartx.com>
---
 drivers/nvme/host/core.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index f320273fc672..1f02e6e49a05 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -2161,6 +2161,12 @@ static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_id_ns *id)
 
 	blk_mq_freeze_queue(ns->disk->queue);
 	ns->lba_shift = id->lbaf[lbaf].ds;
+	if (ns->lba_shift < 9) {
+		pr_warn("%s: bad lba_shift(%d)\n", ns->disk->disk_name, ns->lba_shift);
+		ret = -1;
+		goto out_unfreeze;
+	}
+
 	nvme_set_queue_limits(ns->ctrl, ns->queue);
 
 	if (ns->head->ids.csi == NVME_CSI_ZNS) {
-- 
2.29.2



From Johannes.Thumshirn at wdc.com  Wed Jan 13 11:18:26 2021
From: Johannes.Thumshirn at wdc.com (Johannes Thumshirn)
Date: Wed, 13 Jan 2021 16:18:26 +0000
Subject: [PATCH] nvme: reject the ns when the block size is smaller than a
 sector
References: <20210113160621.98615-1-fengli@smartx.com>
Message-ID: <SN4PR0401MB35985C08E5FFCDF0F5817A9D9BA90@SN4PR0401MB3598.namprd04.prod.outlook.com>

On 13/01/2021 17:07, Li Feng wrote:
> The nvme spec(1.4a, figure 248) says:
> "A value smaller than 9 (i.e., 512 bytes) is not supported."
> 
> Signed-off-by: Li Feng <fengli at smartx.com>
> ---
>  drivers/nvme/host/core.c | 6 ++++++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
> index f320273fc672..1f02e6e49a05 100644
> --- a/drivers/nvme/host/core.c
> +++ b/drivers/nvme/host/core.c
> @@ -2161,6 +2161,12 @@ static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_id_ns *id)
>  
>  	blk_mq_freeze_queue(ns->disk->queue);
>  	ns->lba_shift = id->lbaf[lbaf].ds;
> +	if (ns->lba_shift < 9) {
> +		pr_warn("%s: bad lba_shift(%d)\n", ns->disk->disk_name, ns->lba_shift);
> +		ret = -1;
> +		goto out_unfreeze;
> +	}
> +
>  	nvme_set_queue_limits(ns->ctrl, ns->queue);
>  
>  	if (ns->head->ids.csi == NVME_CSI_ZNS) {
> 


But this only catches a physical block size < 512 for NVMe, not any other block device.

Please fix it for the general case in blk_queue_physical_block_size().

Thanks,
	Johannes


From revanth.rajashekar at intel.com  Wed Jan 13 11:57:18 2021
From: revanth.rajashekar at intel.com (Rajashekar, Revanth)
Date: Wed, 13 Jan 2021 09:57:18 -0700
Subject: [PATCH v2] nvme: Check the PRINFO bit and the Metadata size
 before deciding the host buffer length
In-Reply-To: <20210112183911.GB5050@lst.de>
References: <20210112172941.3911-1-revanth.rajashekar@intel.com>
 <20210112183911.GB5050@lst.de>
Message-ID: <2fa121b7-dc22-6913-7876-ca71249e15bf@intel.com>

Hi Christoph,
Thanks for reviewing.

On 1/12/2021 11:39 AM, Christoph Hellwig wrote:
>> @@ -1546,6 +1546,11 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
>>  	meta_len = (io.nblocks + 1) * ns->ms;
>>  	metadata = nvme_to_user_ptr(io.metadata);
>>
>> +	if (io.control & NVME_RW_PRINFO_PRACT && ns->ms == 8) {
>> +		meta_len = 0;
>> +		metadata = NULL;
>> +	}
>> +
> Wouldn't something like:
>
> 	if ((io.control & NVME_RW_PRINFO_PRACT) &&
> 	    ns->ms == sizeof(struct t10_pi_tuple)) {
> 		/*
> 		 * Protection information is stripped/inserted by the
> 		 * controller.
> 		 */
> 		if (nvme_to_user_ptr(io.metadata))
> 			return -EINVAL;
> 		meta_len = 0;
> 		metadata = NULL;
> 	} else {
> 	 	meta_len = (io.nblocks + 1) * ns->ms;
> 		metadata = nvme_to_user_ptr(io.metadata);
> 	}
>
> make a little more sense?
Yes! it definitely makes more sense.
Will send out a v3 for this patch.

Thanks!
Revanth


From sagi at grimberg.me  Wed Jan 13 13:24:49 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 10:24:49 -0800
Subject: [PATCH] nvme-tcp: fix possible data corruption with bio merges
Message-ID: <20210113182449.1580181-1-sagi@grimberg.me>

When a bio merges, we can get a request that spans multiple
bios, and the overall request payload size is the sum of
all bios. When we calculate how much we need to send
from the existing bio (and bvec), we did not take into
account the iov_iter byte count cap.

Since multipage bvecs support, bvecs can split in the middle
which means that when we account for the last bvec send we
should also take the iov_iter byte count cap as it might be
lower than the last bvec size.

Reported-by: Hao Wang <pkuwangh at gmail.com>
Fixes: 3f2304f8c6d6 ("nvme-tcp: add NVMe over TCP host driver")
Tested-by: Hao Wang <pkuwangh at gmail.com>
Signed-off-by: Sagi Grimberg <sagi at grimberg.me>
---
 drivers/nvme/host/tcp.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 979ee31b8dd1..ad0332477986 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -201,8 +201,9 @@ static inline size_t nvme_tcp_req_cur_offset(struct nvme_tcp_request *req)
 
 static inline size_t nvme_tcp_req_cur_length(struct nvme_tcp_request *req)
 {
-	return min_t(size_t, req->iter.bvec->bv_len - req->iter.iov_offset,
-			req->pdu_len - req->pdu_sent);
+	return min_t(size_t, req->iter.count,
+			min_t(size_t, req->iter.bvec->bv_len - req->iter.iov_offset,
+				req->pdu_len - req->pdu_sent));
 }
 
 static inline size_t nvme_tcp_req_offset(struct nvme_tcp_request *req)
-- 
2.25.1



From hch at lst.de  Wed Jan 13 13:31:42 2021
From: hch at lst.de (Christoph Hellwig)
Date: Wed, 13 Jan 2021 19:31:42 +0100
Subject: [PATCH] nvme-tcp: fix possible data corruption with bio merges
In-Reply-To: <20210113182449.1580181-1-sagi@grimberg.me>
References: <20210113182449.1580181-1-sagi@grimberg.me>
Message-ID: <20210113183142.GA19254@lst.de>

>  static inline size_t nvme_tcp_req_cur_length(struct nvme_tcp_request *req)
>  {
> -	return min_t(size_t, req->iter.bvec->bv_len - req->iter.iov_offset,
> -			req->pdu_len - req->pdu_sent);
> +	return min_t(size_t, req->iter.count,
> +			min_t(size_t, req->iter.bvec->bv_len - req->iter.iov_offset,
> +				req->pdu_len - req->pdu_sent));

We are not supposed to directly poke into an iov_iter.

I suspect this should be something like:

	return min_t(size_t, iov_iter_single_seg_count(&req->iter),
		     req->pdu_len - req->pdu_sent);


From hch at lst.de  Wed Jan 13 13:34:25 2021
From: hch at lst.de (Christoph Hellwig)
Date: Wed, 13 Jan 2021 19:34:25 +0100
Subject: [V3 1/4] nvmet: set right status on error in id-ns handler
In-Reply-To: <20210112214801.GA1505636@dhcp-10-100-145-180.wdc.com>
References: <20210112211410.24742-1-chaitanya.kulkarni@wdc.com>
 <20210112211410.24742-2-chaitanya.kulkarni@wdc.com>
 <20210112214801.GA1505636@dhcp-10-100-145-180.wdc.com>
Message-ID: <20210113183425.GA19474@lst.de>

On Tue, Jan 12, 2021 at 01:48:01PM -0800, Keith Busch wrote:
> On Tue, Jan 12, 2021 at 01:14:07PM -0800, Chaitanya Kulkarni wrote:
> > @@ -541,7 +543,9 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req)
> >  		id->nsattr |= (1 << 0);
> >  	nvmet_put_namespace(ns);
> >  done:
> > -	status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id));
> > +	if (nvmet_copy_to_sgl(req, 0, id, sizeof(*id)) && !status)
> > +		status = NVME_SC_SGL_INVALID_DATA | NVME_SC_DNR;
> 
> If the status is already in error, you don't need to copy out the
> blank struct, right? Shouldn't this be like:
> 
> 	if (!status)
> 		status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id));

Yes.


From sagi at grimberg.me  Wed Jan 13 16:56:39 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 13:56:39 -0800
Subject: [PATCH] nvme-tcp: fix possible data corruption with bio merges
In-Reply-To: <20210113183142.GA19254@lst.de>
References: <20210113182449.1580181-1-sagi@grimberg.me>
 <20210113183142.GA19254@lst.de>
Message-ID: <4aca0d8b-f873-1b78-9468-57e5864d9441@grimberg.me>


>>   static inline size_t nvme_tcp_req_cur_length(struct nvme_tcp_request *req)
>>   {
>> -	return min_t(size_t, req->iter.bvec->bv_len - req->iter.iov_offset,
>> -			req->pdu_len - req->pdu_sent);
>> +	return min_t(size_t, req->iter.count,
>> +			min_t(size_t, req->iter.bvec->bv_len - req->iter.iov_offset,
>> +				req->pdu_len - req->pdu_sent));
> 
> We are not supposed to directly poke into an iov_iter.
> 
> I suspect this should be something like:
> 
> 	return min_t(size_t, iov_iter_single_seg_count(&req->iter),
> 		     req->pdu_len - req->pdu_sent);

You are absolutely right, will send out a v2. thanks.


From sagi at grimberg.me  Wed Jan 13 16:56:57 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 13:56:57 -0800
Subject: [PATCH v2] nvme-tcp: fix possible data corruption with bio merges
Message-ID: <20210113215657.1613817-1-sagi@grimberg.me>

When a bio merges, we can get a request that spans multiple
bios, and the overall request payload size is the sum of
all bios. When we calculate how much we need to send
from the existing bio (and bvec), we did not take into
account the iov_iter byte count cap.

Since multipage bvecs support, bvecs can split in the middle
which means that when we account for the last bvec send we
should also take the iov_iter byte count cap as it might be
lower than the last bvec size.

Reported-by: Hao Wang <pkuwangh at gmail.com>
Fixes: 3f2304f8c6d6 ("nvme-tcp: add NVMe over TCP host driver")
Tested-by: Hao Wang <pkuwangh at gmail.com>
Signed-off-by: Sagi Grimberg <sagi at grimberg.me>
---
 drivers/nvme/host/tcp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Changes from v1:
- use iov_iter_single_seg_count instead of poking into the iov_iter

diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 979ee31b8dd1..1ff6d6c5eb41 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -201,7 +201,7 @@ static inline size_t nvme_tcp_req_cur_offset(struct nvme_tcp_request *req)
 
 static inline size_t nvme_tcp_req_cur_length(struct nvme_tcp_request *req)
 {
-	return min_t(size_t, req->iter.bvec->bv_len - req->iter.iov_offset,
+	return min_t(size_t, iov_iter_single_seg_count(&req->iter),
 			req->pdu_len - req->pdu_sent);
 }
 
-- 
2.25.1



From sagi at grimberg.me  Wed Jan 13 17:03:04 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 14:03:04 -0800
Subject: [PATCH] nvme-tcp: Fix warning with CONFIG_DEBUG_PREEMPT
Message-ID: <20210113220304.1615735-1-sagi@grimberg.me>

We shouldn't call smp_processor_id() in a preemptible
context, but this is advisory at best, so instead
call __smp_processor_id().

Fixes: db5ad6b7f8cd ("nvme-tcp: try to send request in queue_rq context")
Reported-by: Or Gerlitz <gerlitz.or at gmail.com>
Reported-by: Yi Zhang <yi.zhang at redhat.com>
Signed-off-by: Sagi Grimberg <sagi at grimberg.me>
---
 drivers/nvme/host/tcp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index f67a442a5188..4f8936751aa3 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -286,7 +286,7 @@ static inline void nvme_tcp_queue_request(struct nvme_tcp_request *req,
 	 * directly, otherwise queue io_work. Also, only do that if we
 	 * are on the same cpu, so we don't introduce contention.
 	 */
-	if (queue->io_cpu == smp_processor_id() &&
+	if (queue->io_cpu == __smp_processor_id() &&
 	    sync && empty && mutex_trylock(&queue->send_mutex)) {
 		queue->more_requests = !last;
 		nvme_tcp_send_all(queue);
-- 
2.25.1



From sagi at grimberg.me  Wed Jan 13 17:04:37 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 14:04:37 -0800
Subject: [V3 2/4] nvmet: remove extra variable in smart log nsid
In-Reply-To: <20210112211410.24742-3-chaitanya.kulkarni@wdc.com>
References: <20210112211410.24742-1-chaitanya.kulkarni@wdc.com>
 <20210112211410.24742-3-chaitanya.kulkarni@wdc.com>
Message-ID: <82384bb5-26d4-3148-f33a-178cb56655f9@grimberg.me>


> @@ -86,23 +86,21 @@ static u16 nvmet_get_smart_log_nsid(struct nvmet_req *req,
>   	}
>   
>   	/* we don't have the right data for file backed ns */
> -	if (!ns->bdev)
> +	if (!req->ns->bdev)
>   		goto out;
>   
> -	host_reads = part_stat_read(ns->bdev, ios[READ]);
> +	host_reads = part_stat_read(req->ns->bdev, ios[READ]);
>   	data_units_read =
> -		DIV_ROUND_UP(part_stat_read(ns->bdev, sectors[READ]), 1000);
> -	host_writes = part_stat_read(ns->bdev, ios[WRITE]);
> +		DIV_ROUND_UP(part_stat_read(req->ns->bdev, sectors[READ]), 1000);
> +	host_writes = part_stat_read(req->ns->bdev, ios[WRITE]);
>   	data_units_written =
> -		DIV_ROUND_UP(part_stat_read(ns->bdev, sectors[WRITE]), 1000);
> +		DIV_ROUND_UP(part_stat_read(req->ns->bdev, sectors[WRITE]), 1000);
>   
>   	put_unaligned_le64(host_reads, &slog->host_reads[0]);
>   	put_unaligned_le64(data_units_read, &slog->data_units_read[0]);
>   	put_unaligned_le64(host_writes, &slog->host_writes[0]);
>   	put_unaligned_le64(data_units_written, &slog->data_units_written[0]);
>   out:
> -	nvmet_put_namespace(ns);
> -

I think the out label can also be eliminated now.


From sagi at grimberg.me  Wed Jan 13 17:06:07 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 14:06:07 -0800
Subject: [V3 3/4] nvmet: remove extra variable in id-desclist
In-Reply-To: <20210112211410.24742-4-chaitanya.kulkarni@wdc.com>
References: <20210112211410.24742-1-chaitanya.kulkarni@wdc.com>
 <20210112211410.24742-4-chaitanya.kulkarni@wdc.com>
Message-ID: <0c1f5c5d-5cf1-4ae6-cbc2-0e221b11cf2a@grimberg.me>

Reviewed-by: Sagi Grimberg <sagi at grimberg.me>


From sagi at grimberg.me  Wed Jan 13 17:06:31 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 14:06:31 -0800
Subject: [V3 4/4] nvmet: remove extra variable in identify ns
In-Reply-To: <20210112211410.24742-5-chaitanya.kulkarni@wdc.com>
References: <20210112211410.24742-1-chaitanya.kulkarni@wdc.com>
 <20210112211410.24742-5-chaitanya.kulkarni@wdc.com>
Message-ID: <37d3d6e0-bf01-4da7-072f-d99fde4294bc@grimberg.me>

Reviewed-by: Sagi Grimberg <sagi at grimberg.me>


From sagi at grimberg.me  Wed Jan 13 17:12:59 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 14:12:59 -0800
Subject: [PATCH] nvme: reject the ns when the block size is smaller than a
 sector
In-Reply-To: <SN4PR0401MB35985C08E5FFCDF0F5817A9D9BA90@SN4PR0401MB3598.namprd04.prod.outlook.com>
References: <20210113160621.98615-1-fengli@smartx.com>
 <SN4PR0401MB35985C08E5FFCDF0F5817A9D9BA90@SN4PR0401MB3598.namprd04.prod.outlook.com>
Message-ID: <87698545-de26-c0ca-01e9-4dc2ddcacc80@grimberg.me>


>> The nvme spec(1.4a, figure 248) says:
>> "A value smaller than 9 (i.e., 512 bytes) is not supported."
>>
>> Signed-off-by: Li Feng <fengli at smartx.com>
>> ---
>>   drivers/nvme/host/core.c | 6 ++++++
>>   1 file changed, 6 insertions(+)
>>
>> diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
>> index f320273fc672..1f02e6e49a05 100644
>> --- a/drivers/nvme/host/core.c
>> +++ b/drivers/nvme/host/core.c
>> @@ -2161,6 +2161,12 @@ static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_id_ns *id)
>>   
>>   	blk_mq_freeze_queue(ns->disk->queue);
>>   	ns->lba_shift = id->lbaf[lbaf].ds;
>> +	if (ns->lba_shift < 9) {
>> +		pr_warn("%s: bad lba_shift(%d)\n", ns->disk->disk_name, ns->lba_shift);
>> +		ret = -1;

Meaningful errno would be useful. Also better to use dev_warn

>> +		goto out_unfreeze;
>> +	}
>> +
>>   	nvme_set_queue_limits(ns->ctrl, ns->queue);
>>   
>>   	if (ns->head->ids.csi == NVME_CSI_ZNS) {
>>
> 
> 
> But this only catches a physical block size < 512 for NVMe, not any other block device.
> 
> Please fix it for the general case in blk_queue_physical_block_size().

We actually call that later and would probably be better to check here..


From sagi at grimberg.me  Wed Jan 13 17:13:45 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 14:13:45 -0800
Subject: [PATCH] nvme: refactor ns->ctrl by request
In-Reply-To: <20210113143627.787-1-minwoo.im.dev@gmail.com>
References: <20210113143627.787-1-minwoo.im.dev@gmail.com>
Message-ID: <03cc0e00-6419-d29c-37b2-c4e090efaf75@grimberg.me>

Reviewed-by: Sagi Grimberg <sagi at grimberg.me>


From sagi at grimberg.me  Wed Jan 13 17:20:34 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 14:20:34 -0800
Subject: [PATCH V2 2/2] nvme: retry commands based on ACRE result
In-Reply-To: <20210113143538.554-3-minwoo.im.dev@gmail.com>
References: <20210113143538.554-1-minwoo.im.dev@gmail.com>
 <20210113143538.554-3-minwoo.im.dev@gmail.com>
Message-ID: <3bd35739-c309-b04a-fbd7-90daee5aeae7@grimberg.me>

> Introduce acre flag for Advanced Command Retry Enable to controller
> instance to decide whether to retry or not in error cases.  This flag is
> set if Set Features for Host Behavior Support with ACRE bit set is
> successfully done during reset_work.
> 
> This patch also fixes nvme_decide_disposition() because all the nvme
> requests are initialized with REQ_FAILFAST_DRIVER to req->cmd_flags

You mean for passthru commands, nvme doesn't control this for other
commands.

> so
> that blk_noretry_request(req) is always true.  Check ctrl->acre first
> and if it's not host path error, then it will be retried.

I suggest to split out this part to its own patch.

> 
> Cc: Chao Leng <lengchao at huawei.com>
> Signed-off-by: Minwoo Im <minwoo.im.dev at gmail.com>
> ---
>   drivers/nvme/host/core.c | 16 ++++++++++++++--
>   drivers/nvme/host/nvme.h |  1 +
>   2 files changed, 15 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
> index a8cee380b3c0..391bb2d08d0f 100644
> --- a/drivers/nvme/host/core.c
> +++ b/drivers/nvme/host/core.c
> @@ -303,8 +303,7 @@ static inline enum nvme_disposition nvme_decide_disposition(struct request *req)
>   	if (likely(nvme_req(req)->status == 0))
>   		return COMPLETE;
>   
> -	if (blk_noretry_request(req) ||
> -	    (nvme_req(req)->status & NVME_SC_DNR) ||
> +	if ((nvme_req(req)->status & NVME_SC_DNR) ||
>   	    nvme_req(req)->retries >= nvme_max_retries)
>   		return COMPLETE;
>   
> @@ -317,6 +316,13 @@ static inline enum nvme_disposition nvme_decide_disposition(struct request *req)
>   			return COMPLETE;
>   	}
>   
> +	if (nvme_req(req)->ctrl->acre) {
> +		if (!nvme_is_path_error(nvme_req(req)->status) &&
> +				!blk_queue_dying(req->q))
> +			return RETRY;
> +	} else if (blk_noretry_request(req))
> +		return COMPLETE;
> +
>   	return RETRY;
>   }
>   
> @@ -2498,6 +2504,8 @@ static int nvme_configure_acre(struct nvme_ctrl *ctrl)
>   	struct nvme_feat_host_behavior *host;
>   	int ret;
>   
> +	ctrl->acre = false;
> +
>   	/* Don't bother enabling the feature if retry delay is not reported */
>   	if (!ctrl->crdt[0] && !ctrl->crdt[1] && !ctrl->crdt[2])
>   		return 0;
> @@ -2509,6 +2517,10 @@ static int nvme_configure_acre(struct nvme_ctrl *ctrl)
>   	host->acre = NVME_ENABLE_ACRE;
>   	ret = nvme_set_features(ctrl, NVME_FEAT_HOST_BEHAVIOR, 0,
>   				host, sizeof(*host), NULL);
> +
> +	if (!ret)
> +		ctrl->acre = true;
> +
>   	kfree(host);
>   	return ret;
>   }
> diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
> index 88a6b97247f5..db8b45e8ffde 100644
> --- a/drivers/nvme/host/nvme.h
> +++ b/drivers/nvme/host/nvme.h
> @@ -270,6 +270,7 @@ struct nvme_ctrl {
>   #ifdef CONFIG_BLK_DEV_ZONED
>   	u32 max_zone_append;
>   #endif
> +	bool acre;
>   	u16 crdt[3];
>   	u16 oncs;
>   	u16 oacs;
> 


From minwoo.im.dev at gmail.com  Wed Jan 13 17:43:16 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Thu, 14 Jan 2021 07:43:16 +0900
Subject: [PATCH V2 2/2] nvme: retry commands based on ACRE result
In-Reply-To: <3bd35739-c309-b04a-fbd7-90daee5aeae7@grimberg.me>
References: <20210113143538.554-1-minwoo.im.dev@gmail.com>
 <20210113143538.554-3-minwoo.im.dev@gmail.com>
 <3bd35739-c309-b04a-fbd7-90daee5aeae7@grimberg.me>
Message-ID: <20210113224316.GA4094@localhost.localdomain>

Hello,

Thanks for your time!

On 21-01-13 14:20:34, Sagi Grimberg wrote:
> > Introduce acre flag for Advanced Command Retry Enable to controller
> > instance to decide whether to retry or not in error cases.  This flag is
> > set if Set Features for Host Behavior Support with ACRE bit set is
> > successfully done during reset_work.
> > 
> > This patch also fixes nvme_decide_disposition() because all the nvme
> > requests are initialized with REQ_FAILFAST_DRIVER to req->cmd_flags
> 
> You mean for passthru commands, nvme doesn't control this for other
> commands.
> 

Oh, I forgot to mention... Thanks for catching this.

> > so
> > that blk_noretry_request(req) is always true.  Check ctrl->acre first
> > and if it's not host path error, then it will be retried.
> 
> I suggest to split out this part to its own patch.
> 

Okay.  I will split it up to two patches:

  - Introducing ACRE flag to controller
  - Check ACRE flag in nvme_decide_disposition()

Thanks!


From sagi at grimberg.me  Wed Jan 13 17:47:18 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 14:47:18 -0800
Subject: [PATCH] nvme-tcp: fix a segmentation fault during io parsing error
In-Reply-To: <20210113115152.69692-1-elad.grupi@dell.com>
References: <20210113115152.69692-1-elad.grupi@dell.com>
Message-ID: <ad9f038b-9920-21da-755c-85f4e2228a22@grimberg.me>

Hey Elad,

> From: Elad Grupi <elad.grupi at dell.com>
> 
>      In case there is an io that contains inline data and it goes to
>      parsing error flow, command response will free command and iov
>      before clearing the data on the socket buffer.
>      This will delay the command response until receive flow is completed.
> 
> Signed-off-by: Elad Grupi <elad.grupi at dell.com>
> ---
>   drivers/nvme/target/tcp.c | 7 ++++++-
>   1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
> index d535080b781f..dea94da4c9ba 100644
> --- a/drivers/nvme/target/tcp.c
> +++ b/drivers/nvme/target/tcp.c
> @@ -146,6 +146,7 @@ static struct workqueue_struct *nvmet_tcp_wq;
>   static struct nvmet_fabrics_ops nvmet_tcp_ops;
>   static void nvmet_tcp_free_cmd(struct nvmet_tcp_cmd *c);
>   static void nvmet_tcp_finish_cmd(struct nvmet_tcp_cmd *cmd);
> +static void nvmet_tcp_queue_response(struct nvmet_req *req);
>   
>   static inline u16 nvmet_tcp_cmd_tag(struct nvmet_tcp_queue *queue,
>   		struct nvmet_tcp_cmd *cmd)
> @@ -476,7 +477,11 @@ static struct nvmet_tcp_cmd *nvmet_tcp_fetch_cmd(struct nvmet_tcp_queue *queue)
>   		nvmet_setup_c2h_data_pdu(queue->snd_cmd);
>   	else if (nvmet_tcp_need_data_in(queue->snd_cmd))
>   		nvmet_setup_r2t_pdu(queue->snd_cmd);
> -	else
> +	else if (nvmet_tcp_has_data_in(queue->snd_cmd) &&
> +			nvmet_tcp_has_inline_data(queue->snd_cmd)) {

This deserves a comment I think.

Did you get a chance to look into what I sent you guys?

> +		nvmet_tcp_queue_response(&queue->snd_cmd->req);
> +		queue->snd_cmd = NULL;
> +	} else
>   		nvmet_setup_response_pdu(queue->snd_cmd);
>   
>   	return queue->snd_cmd;
> 


From sagi at grimberg.me  Wed Jan 13 18:22:10 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 15:22:10 -0800
Subject: [PATCH] nvmet-rdma: Fix NULL deref when setting pi_enable and
 traddr INADDR_ANY
In-Reply-To: <1610280545-57812-1-git-send-email-israelr@nvidia.com>
References: <1610280545-57812-1-git-send-email-israelr@nvidia.com>
Message-ID: <36e7d294-9738-d2a2-2b56-75788707e260@grimberg.me>

FWIW,

Reviewed-by: Sagi Grimberg <sagi at grimberg.me>


From sagi at grimberg.me  Wed Jan 13 18:22:51 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 15:22:51 -0800
Subject: [PATCH] nvme: Constify static attribute_group structs
In-Reply-To: <20210108234147.42151-1-rikard.falkeborn@gmail.com>
References: <20210108234147.42151-1-rikard.falkeborn@gmail.com>
Message-ID: <4d516ec7-6a3a-71d0-4781-9fd2fcc95fa6@grimberg.me>

FWIW,

Reviewed-by: Sagi Grimberg <sagi at grimberg.me>


From sagi at grimberg.me  Wed Jan 13 19:00:22 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 16:00:22 -0800
Subject: [PATCH] nvme: don't intialize hwmon for discovery controllers
Message-ID: <20210114000022.1641939-1-sagi@grimberg.me>

Discovery controllers usually don't support smart log page command.
So when we connect to the discovery controller we see this warning:
nvme nvme0: Failed to read smart log (error 24577)
nvme nvme0: new ctrl: NQN "nqn.2014-08.org.nvmexpress.discovery", addr 192.168.123.1:8009
nvme nvme0: Removing ctrl: NQN "nqn.2014-08.org.nvmexpress.discovery"

Introduce a new helper to understand if the controller is a discovery
controller and use this helper to skip nvme_init_hwmon (also use it in
other places that we check if the controller is a discovery controller).

Fixes: 400b6a7b13a3 ("nvme: Add hardware monitoring support")
Signed-off-by: Sagi Grimberg <sagi at grimberg.me>
---
 drivers/nvme/host/core.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index fff49e544fdf..a7dbc3ef79f4 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -2855,6 +2855,11 @@ static const struct attribute_group *nvme_subsys_attrs_groups[] = {
 	NULL,
 };
 
+static inline bool nvme_discovery_ctrl(struct nvme_ctrl *ctrl)
+{
+	return ctrl->opts && ctrl->opts->discovery_nqn;
+}
+
 static bool nvme_validate_cntlid(struct nvme_subsystem *subsys,
 		struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
 {
@@ -2874,7 +2879,7 @@ static bool nvme_validate_cntlid(struct nvme_subsystem *subsys,
 		}
 
 		if ((id->cmic & NVME_CTRL_CMIC_MULTI_CTRL) ||
-		    (ctrl->opts && ctrl->opts->discovery_nqn))
+		    nvme_discovery_ctrl(ctrl))
 			continue;
 
 		dev_err(ctrl->device,
@@ -3143,7 +3148,7 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
 			goto out_free;
 		}
 
-		if (!ctrl->opts->discovery_nqn && !ctrl->kas) {
+		if (!nvme_discovery_ctrl(ctrl) && !ctrl->kas) {
 			dev_err(ctrl->device,
 				"keep-alive support is mandatory for fabrics\n");
 			ret = -EINVAL;
@@ -3183,7 +3188,7 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
 	if (ret < 0)
 		return ret;
 
-	if (!ctrl->identified) {
+	if (!ctrl->identified && !nvme_discovery_ctrl(ctrl)) {
 		ret = nvme_hwmon_init(ctrl);
 		if (ret < 0)
 			return ret;
-- 
2.25.1



From sagi at grimberg.me  Wed Jan 13 19:10:39 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 16:10:39 -0800
Subject: [PATCH 0/3] few simple cleanups for nvme-tcp host
Message-ID: <20210114001039.1644461-1-sagi@grimberg.me>

No real bug fix here, but some useful cleanups.

Sagi Grimberg (3):
  nvme-tcp: fix wrong setting of request iov_iter
  nvme-tcp: get rid of unused helper function
  nvme-tcp: pass multipage bvec to request iov_iter

 drivers/nvme/host/tcp.c | 25 +++++++++++--------------
 1 file changed, 11 insertions(+), 14 deletions(-)

-- 
2.25.1



From sagi at grimberg.me  Wed Jan 13 19:15:51 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 16:15:51 -0800
Subject: [PATCH v2 0/6] avoid repeated request completion and IO error
In-Reply-To: <20210107033149.15701-1-lengchao@huawei.com>
References: <20210107033149.15701-1-lengchao@huawei.com>
Message-ID: <879d04a5-c52e-4d21-5003-d369ab5cdaee@grimberg.me>

> First avoid repeated request completion for nvmf_fail_nonready_command.
> Second avoid IO error and repeated request completion for queue_rq.

Maybe this is me chiming in v2, but what is this fixing? what
is the bug you are seeing?


From sagi at grimberg.me  Wed Jan 13 19:17:01 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 16:17:01 -0800
Subject: [PATCH v2 1/6] blk-mq: introduce blk_mq_set_request_complete
In-Reply-To: <20210107033149.15701-2-lengchao@huawei.com>
References: <20210107033149.15701-1-lengchao@huawei.com>
 <20210107033149.15701-2-lengchao@huawei.com>
Message-ID: <6ce3e173-4ac3-e84d-88ca-76057a8d8e1e@grimberg.me>


> In some scenarios, nvme need setting the state of request to
> MQ_RQ_COMPLETE. So add an inline function blk_mq_set_request_complete.
> For details, see the subsequent patches.

Its kinda difficult to understand the meaning of all of this...
the cover letter tells us nothing, and patches 1/2 also tells us
to see subsequent patches.

This is saved in the git change log history, so please try
describe what it is you are going with this, even if there are
overlaps between patches.


From sagi at grimberg.me  Wed Jan 13 19:19:47 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 16:19:47 -0800
Subject: [PATCH v2 4/6] nvme-rdma: avoid IO error and repeated request
 completion
In-Reply-To: <20210107033149.15701-5-lengchao@huawei.com>
References: <20210107033149.15701-1-lengchao@huawei.com>
 <20210107033149.15701-5-lengchao@huawei.com>
Message-ID: <07e41b4f-914a-11e8-5638-e2d6408feb3f@grimberg.me>


> When a request is queued failed, blk_status_t is directly returned
> to the blk-mq. If blk_status_t is not BLK_STS_RESOURCE,
> BLK_STS_DEV_RESOURCE, BLK_STS_ZONE_RESOURCE, blk-mq call
> blk_mq_end_request to complete the request with BLK_STS_IOERR.
> In two scenarios, the request should be retried and may succeed.
> First, if work with nvme multipath, the request may be retried
> successfully in another path, because the error is probably related to
> the path. Second, if work without multipath software, the request may
> be retried successfully after error recovery.
> If the request is complete with BLK_STS_IOERR in blk_mq_dispatch_rq_list.
> The state of request may be changed to MQ_RQ_IN_FLIGHT. If free the
> request asynchronously such as in nvme_submit_user_cmd, in extreme
> scenario the request will be repeated freed in tear down.
> If a non-resource error occurs in queue_rq, should directly call
> nvme_complete_rq to complete request and set the state of request to
> MQ_RQ_COMPLETE. nvme_complete_rq will decide to retry, fail over or end
> the request.
> 
> Signed-off-by: Chao Leng <lengchao at huawei.com>
> ---
>   drivers/nvme/host/rdma.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
> index df9f6f4549f1..4a89bf44ecdc 100644
> --- a/drivers/nvme/host/rdma.c
> +++ b/drivers/nvme/host/rdma.c
> @@ -2093,7 +2093,7 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
>   unmap_qe:
>   	ib_dma_unmap_single(dev, req->sqe.dma, sizeof(struct nvme_command),
>   			    DMA_TO_DEVICE);
> -	return ret;
> +	return nvme_try_complete_failed_req(rq, ret);

I don't understand this. There are errors that may not be related to
anything that is pathing related (sw bug, memory leak, mapping error,
etc, etc) why should we return this one-shot error?


From sagi at grimberg.me  Wed Jan 13 19:34:51 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 16:34:51 -0800
Subject: fabrics connect cmd with a non-zero reserved value
In-Reply-To: <SN6PR1901MB202957C808A7D493E252D873EED00@SN6PR1901MB2029.namprd19.prod.outlook.com>
References: <SN6PR1901MB202957C808A7D493E252D873EED00@SN6PR1901MB2029.namprd19.prod.outlook.com>
Message-ID: <6e271be1-088b-5a23-0eec-23578f707c28@grimberg.me>


> Hello,
> We see that when executing nvme connect cmd (Opcode: 0x7f Fabric Cmd)
> The host is submitting the cmd with reserved filed set to non-zero value - which is out of spec.
> Seems like this issue is not only for connect but also for other fabrics cmds.
> 
> Here is a packet capture for nvme connect :
> 
>      NVM Express Fabrics (Cmd)
>          Opcode: 0x7f Fabric Cmd
>          [Fabric Cqe in: 302]
>          Reserved: 0x40
>          Command ID: 0x0000
>          Fabric Cmd Type: Connect (0x01)
>          Reserved: 00000000000000000000000000000000000000
>          SGL1
>          Record Format: 0x0000
>          Queue ID: 0x0000
>          SQ Size: 0x001f
>          Connect Attributes: 0x00
>          Reserved: 00
>          Keep Alive Timeout: 15000ms
>          Reserved: 000000000000000000000000
>      Data
>          Host Identifier: f1aa9784-195b-4814-893d-44f90a6a92d9
>          Controller ID: 0xffff
>          Reserved: 000000000000000000000000000000000000000000000000000000000000000000000000...
>          Subsystem NQN: nqn.2015-10.com.dell:dellemc-powerstore-23b5145591975EDFF2FE
>          Host NQN: nqn.2014-08.org.nvmexpress:uuid:nc5199007
>          Reserved: 000000000000000000000000000000000000000000000000000000000000000000000000...
> 
> 0x40 value is corresponding to PSDT, in a normal (non-fabric) nvme cmd, PSDT field exists.
> Do we expect for the same for fabric cmd?
> If so, the spec can't mark the second byte of connect cmd as reserved.
> Based on nvme spec:
> "A reserved bit, byte, word, field, or register shall be cleared to 0h, or in accordance with a future extension to this specification"
> 
> Is this a real bug or a spec bug?

We shouldn't be setting reserved bits. But from what I see, we zero the 
nvme commands before setting it so this is strange to me..


From sagi at grimberg.me  Wed Jan 13 20:10:05 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 17:10:05 -0800
Subject: fabrics connect cmd with a non-zero reserved value
In-Reply-To: <6e271be1-088b-5a23-0eec-23578f707c28@grimberg.me>
References: <SN6PR1901MB202957C808A7D493E252D873EED00@SN6PR1901MB2029.namprd19.prod.outlook.com>
 <6e271be1-088b-5a23-0eec-23578f707c28@grimberg.me>
Message-ID: <69465d48-5a63-5c49-50aa-39c4f921ed4a@grimberg.me>



On 1/13/21 4:34 PM, Sagi Grimberg wrote:
> 
>> Hello,
>> We see that when executing nvme connect cmd (Opcode: 0x7f Fabric Cmd)
>> The host is submitting the cmd with reserved filed set to non-zero 
>> value - which is out of spec.
>> Seems like this issue is not only for connect but also for other 
>> fabrics cmds.
>>
>> Here is a packet capture for nvme connect :
>>
>> ???? NVM Express Fabrics (Cmd)
>> ???????? Opcode: 0x7f Fabric Cmd
>> ???????? [Fabric Cqe in: 302]
>> ???????? Reserved: 0x40
>> ???????? Command ID: 0x0000
>> ???????? Fabric Cmd Type: Connect (0x01)
>> ???????? Reserved: 00000000000000000000000000000000000000
>> ???????? SGL1
>> ???????? Record Format: 0x0000
>> ???????? Queue ID: 0x0000
>> ???????? SQ Size: 0x001f
>> ???????? Connect Attributes: 0x00
>> ???????? Reserved: 00
>> ???????? Keep Alive Timeout: 15000ms
>> ???????? Reserved: 000000000000000000000000
>> ???? Data
>> ???????? Host Identifier: f1aa9784-195b-4814-893d-44f90a6a92d9
>> ???????? Controller ID: 0xffff
>> ???????? Reserved: 
>> 000000000000000000000000000000000000000000000000000000000000000000000000... 
>>
>> ???????? Subsystem NQN: 
>> nqn.2015-10.com.dell:dellemc-powerstore-23b5145591975EDFF2FE
>> ???????? Host NQN: nqn.2014-08.org.nvmexpress:uuid:nc5199007
>> ???????? Reserved: 
>> 000000000000000000000000000000000000000000000000000000000000000000000000... 
>>
>>
>> 0x40 value is corresponding to PSDT, in a normal (non-fabric) nvme 
>> cmd, PSDT field exists.
>> Do we expect for the same for fabric cmd?
>> If so, the spec can't mark the second byte of connect cmd as reserved.
>> Based on nvme spec:
>> "A reserved bit, byte, word, field, or register shall be cleared to 
>> 0h, or in accordance with a future extension to this specification"
>>
>> Is this a real bug or a spec bug?
> 
> We shouldn't be setting reserved bits. But from what I see, we zero the 
> nvme commands before setting it so this is strange to me..

OK, now I see the issue.

This appears to me this would be an issue with the spec. As the connect
data (like any command payload) is coming in the form of an sgl.

Adding Fred for this question.


From sagi at grimberg.me  Wed Jan 13 20:11:10 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 17:11:10 -0800
Subject: [PATCH] nvme-rdma: avoid repeated request completion for
 concurrent nvme_rdma_timeout
In-Reply-To: <20210106063635.7452-1-lengchao@huawei.com>
References: <20210106063635.7452-1-lengchao@huawei.com>
Message-ID: <002e7d37-433c-f8fa-f460-bfb2447d6bc0@grimberg.me>


On 1/5/21 10:36 PM, Chao Leng wrote:
> A crash happens when inject completing request long time(nearly 30s).
> Each name space has a request queue, when inject completing request long
> time, multi request queues may has time out requests at the same time,
> nvme_rdma_timeout will execute concurrently. Multi requests in different
> request queues may be queued in the same rdma queue, multi
> nvme_rdma_timeout may call nvme_rdma_stop_queue at the same time.
> The first nvme_rdma_timeout will clear NVME_RDMA_Q_LIVE and continue
> stopping the rdma queue(drain qp), but the others check NVME_RDMA_Q_LIVE
> is already cleared, and then directly complete the requests, but the
> rdma queue may be not stopped and the request may be already completed
> in qp and wait treated, the request will be repeated completed.
> Add a multex lock to serialize nvme_rdma_stop_queue.

This looks reasonable to me,

Mind sending one for nvme-tcp as well?

> 
> Signed-off-by: Chao Leng <lengchao at huawei.com>
> ---
>   drivers/nvme/host/rdma.c | 15 +++++++++++----
>   1 file changed, 11 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
> index df9f6f4549f1..d5c66e3eeb4a 100644
> --- a/drivers/nvme/host/rdma.c
> +++ b/drivers/nvme/host/rdma.c
> @@ -97,6 +97,7 @@ struct nvme_rdma_queue {
>   	struct completion	cm_done;
>   	bool			pi_support;
>   	int			cq_size;
> +	struct mutex		queue_lock;
>   };
>   
>   struct nvme_rdma_ctrl {
> @@ -579,6 +580,7 @@ static int nvme_rdma_alloc_queue(struct nvme_rdma_ctrl *ctrl,
>   	int ret;
>   
>   	queue = &ctrl->queues[idx];
> +	mutex_init(&queue->queue_lock);
>   	queue->ctrl = ctrl;
>   	if (idx && ctrl->ctrl.max_integrity_segments)
>   		queue->pi_support = true;
> @@ -598,7 +600,8 @@ static int nvme_rdma_alloc_queue(struct nvme_rdma_ctrl *ctrl,
>   	if (IS_ERR(queue->cm_id)) {
>   		dev_info(ctrl->ctrl.device,
>   			"failed to create CM ID: %ld\n", PTR_ERR(queue->cm_id));
> -		return PTR_ERR(queue->cm_id);
> +		ret = PTR_ERR(queue->cm_id);
> +		goto out_destroy_mutex;
>   	}
>   
>   	if (ctrl->ctrl.opts->mask & NVMF_OPT_HOST_TRADDR)
> @@ -628,6 +631,8 @@ static int nvme_rdma_alloc_queue(struct nvme_rdma_ctrl *ctrl,
>   out_destroy_cm_id:
>   	rdma_destroy_id(queue->cm_id);
>   	nvme_rdma_destroy_queue_ib(queue);
> +out_destroy_mutex:
> +	mutex_destroy(&queue->queue_lock);
>   	return ret;
>   }
>   
> @@ -639,9 +644,10 @@ static void __nvme_rdma_stop_queue(struct nvme_rdma_queue *queue)
>   
>   static void nvme_rdma_stop_queue(struct nvme_rdma_queue *queue)
>   {
> -	if (!test_and_clear_bit(NVME_RDMA_Q_LIVE, &queue->flags))
> -		return;
> -	__nvme_rdma_stop_queue(queue);
> +	mutex_lock(&queue->queue_lock);
> +	if (test_and_clear_bit(NVME_RDMA_Q_LIVE, &queue->flags))
> +		__nvme_rdma_stop_queue(queue);
> +	mutex_unlock(&queue->queue_lock);
>   }
>   
>   static void nvme_rdma_free_queue(struct nvme_rdma_queue *queue)
> @@ -649,6 +655,7 @@ static void nvme_rdma_free_queue(struct nvme_rdma_queue *queue)
>   	if (!test_and_clear_bit(NVME_RDMA_Q_ALLOCATED, &queue->flags))
>   		return;
>   
> +	mutex_destroy(&queue->queue_lock);
>   	nvme_rdma_destroy_queue_ib(queue);
>   	rdma_destroy_id(queue->cm_id);
>   }
> 


From sagi at grimberg.me  Wed Jan 13 20:15:18 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 17:15:18 -0800
Subject: [PATCH] nvme-rdma: avoid repeated request completion for
 concurrent nvme_rdma_timeout
In-Reply-To: <002e7d37-433c-f8fa-f460-bfb2447d6bc0@grimberg.me>
References: <20210106063635.7452-1-lengchao@huawei.com>
 <002e7d37-433c-f8fa-f460-bfb2447d6bc0@grimberg.me>
Message-ID: <8a5b4b58-98be-4da1-a769-dc173d2a3be0@grimberg.me>


> On 1/5/21 10:36 PM, Chao Leng wrote:
>> A crash happens when inject completing request long time(nearly 30s).
>> Each name space has a request queue, when inject completing request long
>> time, multi request queues may has time out requests at the same time,
>> nvme_rdma_timeout will execute concurrently. Multi requests in different
>> request queues may be queued in the same rdma queue, multi
>> nvme_rdma_timeout may call nvme_rdma_stop_queue at the same time.
>> The first nvme_rdma_timeout will clear NVME_RDMA_Q_LIVE and continue
>> stopping the rdma queue(drain qp), but the others check NVME_RDMA_Q_LIVE
>> is already cleared, and then directly complete the requests, but the
>> rdma queue may be not stopped and the request may be already completed
>> in qp and wait treated, the request will be repeated completed.
>> Add a multex lock to serialize nvme_rdma_stop_queue.
> 
> This looks reasonable to me,
> 
> Mind sending one for nvme-tcp as well?

BTW, I'm assuming you mean use-after-free or double completion when you
are referring to repeated completions? I think it would be easier to
understand if you just say that completing request before the qp is
fully drained may lead to a use-after-free condition.


From sagi at grimberg.me  Wed Jan 13 20:27:17 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 17:27:17 -0800
Subject: [PATCH v1 net-next 00/15] nvme-tcp receive offloads
In-Reply-To: <20201207210649.19194-1-borisp@mellanox.com>
References: <20201207210649.19194-1-borisp@mellanox.com>
Message-ID: <69f9a7c3-e2ab-454a-2713-2e9c9dea4e47@grimberg.me>

Hey Boris, sorry for some delays on my end...

I saw some long discussions on this set with David, what is
the status here?

I'll take some more look into the patches, but if you
addressed the feedback from the last iteration I don't
expect major issues with this patch set (at least from
nvme-tcp side).

> Changes since RFC v1:
> =========================================
> * Split mlx5 driver patches to several commits
> * Fix nvme-tcp handling of recovery flows. In particular, move queue offlaod
>    init/teardown to the start/stop functions.

I'm assuming that you tested controller resets and network hiccups
during traffic right?


From chaitanya.kulkarni at wdc.com  Wed Jan 13 20:33:50 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Wed, 13 Jan 2021 17:33:50 -0800
Subject: [PATCH V4 0/4] nvmet: admin-cmd related cleanups and a fix
Message-ID: <20210114013354.33946-1-chaitanya.kulkarni@wdc.com>

Hi,

There are three functions where local variable ns is used instead of
using req->ns which leads to duplicate nvmet_put_namespace() calls.
We can just use req->ns and not the local variable to avoid duplicate
calls.

The first patch sets the right error status code when namespace is not
found in nvmet_execute_identify_ns().

I've tested this series with nvme blktests, all the testcases are
passing.

-ck

Changes from V3:-

1. Don't copy zeroed buffer in case of invalid ns for id-ns handler.
2. Remove the out label in smart log nsid.

Changes from V2:-

1. Rebase and retest on the latest nvme-5.11.
2. Add ns status error patch at the front of the series.

Changes from V1:-

1. Rebase and retest on the latest nvme-5.11.

Chaitanya Kulkarni (4):
  nvmet: set right status on error in id-ns handler
  nvmet: remove extra variable in smart log nsid
  nvmet: remove extra variable in id-desclist
  nvmet: remove extra variable in identify ns

 drivers/nvme/target/admin-cmd.c | 77 ++++++++++++++++-----------------
 1 file changed, 38 insertions(+), 39 deletions(-)

#./check tests/nvme
nvme/002 (create many subsystems and test discovery)         [passed]
    runtime    ...  27.652s
nvme/003 (test if we're sending keep-alives to a discovery controller) [passed]
    runtime  10.136s  ...  10.137s
nvme/004 (test nvme and nvmet UUID NS descriptors)           [passed]
    runtime  1.730s  ...  1.691s
nvme/005 (reset local loopback target)                       [not run]
    nvme_core module does not have parameter multipath
nvme/006 (create an NVMeOF target with a block device-backed ns) [passed]
    runtime  0.113s  ...  0.114s
nvme/007 (create an NVMeOF target with a file-backed ns)     [passed]
    runtime  0.074s  ...  0.080s
nvme/008 (create an NVMeOF host with a block device-backed ns) [passed]
    runtime  1.720s  ...  1.703s
nvme/009 (create an NVMeOF host with a file-backed ns)       [passed]
    runtime  1.683s  ...  1.653s
nvme/010 (run data verification fio job on NVMeOF block device-backed ns) [passed]
    runtime  25.213s  ...  26.554s
nvme/011 (run data verification fio job on NVMeOF file-backed ns) [passed]
    runtime  257.846s  ...  235.864s
nvme/012 (run mkfs and data verification fio job on NVMeOF block device-backed ns) [passed]
    runtime  47.453s  ...  51.182s
nvme/013 (run mkfs and data verification fio job on NVMeOF file-backed ns) [passed]
    runtime  249.408s  ...  273.498s
nvme/014 (flush a NVMeOF block device-backed ns)             [passed]
    runtime  22.446s  ...  21.439s
nvme/015 (unit test for NVMe flush for file backed ns)       [passed]
    runtime  18.614s  ...  19.769s
nvme/016 (create/delete many NVMeOF block device-backed ns and test discovery) [passed]
    runtime  16.945s  ...  16.443s
nvme/017 (create/delete many file-ns and test discovery)     [passed]
    runtime  17.179s  ...  17.091s
nvme/018 (unit test NVMe-oF out of range access on a file backend) [passed]
    runtime  1.676s  ...  1.678s
nvme/019 (test NVMe DSM Discard command on NVMeOF block-device ns) [passed]
    runtime  1.701s  ...  1.713s
nvme/020 (test NVMe DSM Discard command on NVMeOF file-backed ns) [passed]
    runtime  1.662s  ...  1.665s
nvme/021 (test NVMe list command on NVMeOF file-backed ns)   [passed]
    runtime  1.666s  ...  1.657s
nvme/022 (test NVMe reset command on NVMeOF file-backed ns)  [passed]
    runtime  2.099s  ...  2.075s
nvme/023 (test NVMe smart-log command on NVMeOF block-device ns) [passed]
    runtime  1.699s  ...  1.687s
nvme/024 (test NVMe smart-log command on NVMeOF file-backed ns) [passed]
    runtime  1.659s  ...  1.667s
nvme/025 (test NVMe effects-log command on NVMeOF file-backed ns) [passed]
    runtime  1.649s  ...  1.651s
nvme/026 (test NVMe ns-descs command on NVMeOF file-backed ns) [passed]
    runtime  1.658s  ...  1.665s
nvme/027 (test NVMe ns-rescan command on NVMeOF file-backed ns) [passed]
    runtime  1.665s  ...  1.660s
nvme/028 (test NVMe list-subsys command on NVMeOF file-backed ns) [passed]
    runtime  1.663s  ...  1.660s
nvme/029 (test userspace IO via nvme-cli read/write interface) [passed]
    runtime  2.025s  ...  2.037s
nvme/030 (ensure the discovery generation counter is updated appropriately) [passed]
    runtime  0.317s  ...  0.313s
nvme/031 (test deletion of NVMeOF controllers immediately after setup) [passed]
    runtime  5.559s  ...  5.553s
nvme/038 (test deletion of NVMeOF subsystem without enabling) [passed]
    runtime  0.046s  ...  0.044s

# gitlog -5
6f388312bf5b (HEAD -> nvme-5.11) nvmet: remove extra variable in identify ns
733d50382d90 nvmet: remove extra variable in id-desclist
d982b2b03fc0 nvmet: remove extra variable in smart log nsid
4a458a76be0e nvmet: set right status on error in id-ns handler
239055c858f5 Merge branch 'nvme-5.11' of git://git.infradead.org/nvme into nvme-5.11

-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Wed Jan 13 20:33:51 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Wed, 13 Jan 2021 17:33:51 -0800
Subject: [PATCH V4 1/4] nvmet: set right status on error in id-ns handler
In-Reply-To: <20210114013354.33946-1-chaitanya.kulkarni@wdc.com>
References: <20210114013354.33946-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210114013354.33946-2-chaitanya.kulkarni@wdc.com>

The function nvmet_execute_identify_ns() doesn't set the status if call
to nvmet_find_namespace() fails. In that case we set the status of the
request to the value return by the nvmet_copy_sgl().

Set the status to NVME_SC_INVALID_NS and adjust the code such that
request will have the right status on nvmet_find_namespace() failure.

Without this patch :-
NVME Identify Namespace 3:
nsze    : 0
ncap    : 0
nuse    : 0
nsfeat  : 0
nlbaf   : 0
flbas   : 0
mc      : 0
dpc     : 0
dps     : 0
nmic    : 0
rescap  : 0
fpi     : 0
dlfeat  : 0
nawun   : 0
nawupf  : 0
nacwu   : 0
nabsn   : 0
nabo    : 0
nabspf  : 0
noiob   : 0
nvmcap  : 0
mssrl   : 0
mcl     : 0
msrc    : 0
nsattr	: 0
nvmsetid: 0
anagrpid: 0
endgid  : 0
nguid   : 00000000000000000000000000000000
eui64   : 0000000000000000
lbaf  0 : ms:0   lbads:0  rp:0 (in use)

With this patch-series :-
feb3b88b501e (HEAD -> nvme-5.11) nvmet: remove extra variable in identify ns
6302aa67210a nvmet: remove extra variable in id-desclist
ed57951da453 nvmet: remove extra variable in smart log nsid
be384b8c24dc nvmet: set right status on error in id-ns handler

NVMe status: INVALID_NS: The namespace or the format of that namespace is invalid(0xb)

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/target/admin-cmd.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index 8d90235e4fcc..dc1ea468b182 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -487,8 +487,10 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req)
 
 	/* return an all zeroed buffer if we can't find an active namespace */
 	ns = nvmet_find_namespace(ctrl, req->cmd->identify.nsid);
-	if (!ns)
+	if (!ns) {
+		status = NVME_SC_INVALID_NS;
 		goto done;
+	}
 
 	nvmet_ns_revalidate(ns);
 
@@ -541,7 +543,9 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req)
 		id->nsattr |= (1 << 0);
 	nvmet_put_namespace(ns);
 done:
-	status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id));
+	if (!status)
+		status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id));
+
 	kfree(id);
 out:
 	nvmet_req_complete(req, status);
-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Wed Jan 13 20:33:52 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Wed, 13 Jan 2021 17:33:52 -0800
Subject: [PATCH V4 2/4] nvmet: remove extra variable in smart log nsid
In-Reply-To: <20210114013354.33946-1-chaitanya.kulkarni@wdc.com>
References: <20210114013354.33946-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210114013354.33946-3-chaitanya.kulkarni@wdc.com>

We remove the extra local variable struct nvmet_ns in
nvmet_get_smart_log_nsid() since req already has ns member that can be
reused, this also eliminates the explicit call to nvmet_put_namespace()
which is already present in the request completion path.

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/target/admin-cmd.c | 20 +++++++++-----------
 1 file changed, 9 insertions(+), 11 deletions(-)

diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index dc1ea468b182..de804d9762dd 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -74,11 +74,11 @@ static void nvmet_execute_get_log_page_error(struct nvmet_req *req)
 static u16 nvmet_get_smart_log_nsid(struct nvmet_req *req,
 		struct nvme_smart_log *slog)
 {
-	struct nvmet_ns *ns;
 	u64 host_reads, host_writes, data_units_read, data_units_written;
 
-	ns = nvmet_find_namespace(req->sq->ctrl, req->cmd->get_log_page.nsid);
-	if (!ns) {
+	req->ns = nvmet_find_namespace(req->sq->ctrl,
+				       req->cmd->get_log_page.nsid);
+	if (!req->ns) {
 		pr_err("Could not find namespace id : %d\n",
 				le32_to_cpu(req->cmd->get_log_page.nsid));
 		req->error_loc = offsetof(struct nvme_rw_command, nsid);
@@ -86,22 +86,20 @@ static u16 nvmet_get_smart_log_nsid(struct nvmet_req *req,
 	}
 
 	/* we don't have the right data for file backed ns */
-	if (!ns->bdev)
-		goto out;
+	if (!req->ns->bdev)
+		return NVME_SC_SUCCESS;
 
-	host_reads = part_stat_read(ns->bdev, ios[READ]);
+	host_reads = part_stat_read(req->ns->bdev, ios[READ]);
 	data_units_read =
-		DIV_ROUND_UP(part_stat_read(ns->bdev, sectors[READ]), 1000);
-	host_writes = part_stat_read(ns->bdev, ios[WRITE]);
+		DIV_ROUND_UP(part_stat_read(req->ns->bdev, sectors[READ]), 1000);
+	host_writes = part_stat_read(req->ns->bdev, ios[WRITE]);
 	data_units_written =
-		DIV_ROUND_UP(part_stat_read(ns->bdev, sectors[WRITE]), 1000);
+		DIV_ROUND_UP(part_stat_read(req->ns->bdev, sectors[WRITE]), 1000);
 
 	put_unaligned_le64(host_reads, &slog->host_reads[0]);
 	put_unaligned_le64(data_units_read, &slog->data_units_read[0]);
 	put_unaligned_le64(host_writes, &slog->host_writes[0]);
 	put_unaligned_le64(data_units_written, &slog->data_units_written[0]);
-out:
-	nvmet_put_namespace(ns);
 
 	return NVME_SC_SUCCESS;
 }
-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Wed Jan 13 20:33:53 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Wed, 13 Jan 2021 17:33:53 -0800
Subject: [PATCH V4 3/4] nvmet: remove extra variable in id-desclist
In-Reply-To: <20210114013354.33946-1-chaitanya.kulkarni@wdc.com>
References: <20210114013354.33946-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210114013354.33946-4-chaitanya.kulkarni@wdc.com>

We remove the extra local variable struct nvmet_ns in
nvmet_execute_identify_desclist() since req already has ns member that
can be reused, this also eliminates the explicit call to
nvmet_put_namespace() which is already present in the request
completion path.

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/target/admin-cmd.c | 20 +++++++++-----------
 1 file changed, 9 insertions(+), 11 deletions(-)

diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index de804d9762dd..1cc61ca42a7d 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -605,37 +605,35 @@ static u16 nvmet_copy_ns_identifier(struct nvmet_req *req, u8 type, u8 len,
 
 static void nvmet_execute_identify_desclist(struct nvmet_req *req)
 {
-	struct nvmet_ns *ns;
 	u16 status = 0;
 	off_t off = 0;
 
-	ns = nvmet_find_namespace(req->sq->ctrl, req->cmd->identify.nsid);
-	if (!ns) {
+	req->ns = nvmet_find_namespace(req->sq->ctrl, req->cmd->identify.nsid);
+	if (!req->ns) {
 		req->error_loc = offsetof(struct nvme_identify, nsid);
 		status = NVME_SC_INVALID_NS | NVME_SC_DNR;
 		goto out;
 	}
 
-	if (memchr_inv(&ns->uuid, 0, sizeof(ns->uuid))) {
+	if (memchr_inv(&req->ns->uuid, 0, sizeof(req->ns->uuid))) {
 		status = nvmet_copy_ns_identifier(req, NVME_NIDT_UUID,
 						  NVME_NIDT_UUID_LEN,
-						  &ns->uuid, &off);
+						  &req->ns->uuid, &off);
 		if (status)
-			goto out_put_ns;
+			goto out;
 	}
-	if (memchr_inv(ns->nguid, 0, sizeof(ns->nguid))) {
+	if (memchr_inv(req->ns->nguid, 0, sizeof(req->ns->nguid))) {
 		status = nvmet_copy_ns_identifier(req, NVME_NIDT_NGUID,
 						  NVME_NIDT_NGUID_LEN,
-						  &ns->nguid, &off);
+						  &req->ns->nguid, &off);
 		if (status)
-			goto out_put_ns;
+			goto out;
 	}
 
 	if (sg_zero_buffer(req->sg, req->sg_cnt, NVME_IDENTIFY_DATA_SIZE - off,
 			off) != NVME_IDENTIFY_DATA_SIZE - off)
 		status = NVME_SC_INTERNAL | NVME_SC_DNR;
-out_put_ns:
-	nvmet_put_namespace(ns);
+
 out:
 	nvmet_req_complete(req, status);
 }
-- 
2.22.1



From chaitanya.kulkarni at wdc.com  Wed Jan 13 20:33:54 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Wed, 13 Jan 2021 17:33:54 -0800
Subject: [PATCH V4 4/4] nvmet: remove extra variable in identify ns
In-Reply-To: <20210114013354.33946-1-chaitanya.kulkarni@wdc.com>
References: <20210114013354.33946-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210114013354.33946-5-chaitanya.kulkarni@wdc.com>

We remove the extra local variable struct nvmet_ns in
nvmet_execute_identify_ns() since req already has ns member that can be
reused, this also eliminates the explicit call to nvmet_put_namespace()
which is already present in the request completion path.

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/target/admin-cmd.c | 31 +++++++++++++++----------------
 1 file changed, 15 insertions(+), 16 deletions(-)

diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index 1cc61ca42a7d..613a4d8feac1 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -467,7 +467,6 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
 static void nvmet_execute_identify_ns(struct nvmet_req *req)
 {
 	struct nvmet_ctrl *ctrl = req->sq->ctrl;
-	struct nvmet_ns *ns;
 	struct nvme_id_ns *id;
 	u16 status = 0;
 
@@ -484,20 +483,21 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req)
 	}
 
 	/* return an all zeroed buffer if we can't find an active namespace */
-	ns = nvmet_find_namespace(ctrl, req->cmd->identify.nsid);
-	if (!ns) {
+	req->ns = nvmet_find_namespace(ctrl, req->cmd->identify.nsid);
+	if (!req->ns) {
 		status = NVME_SC_INVALID_NS;
 		goto done;
 	}
 
-	nvmet_ns_revalidate(ns);
+	nvmet_ns_revalidate(req->ns);
 
 	/*
 	 * nuse = ncap = nsze isn't always true, but we have no way to find
 	 * that out from the underlying device.
 	 */
-	id->ncap = id->nsze = cpu_to_le64(ns->size >> ns->blksize_shift);
-	switch (req->port->ana_state[ns->anagrpid]) {
+	id->ncap = id->nsze =
+		cpu_to_le64(req->ns->size >> req->ns->blksize_shift);
+	switch (req->port->ana_state[req->ns->anagrpid]) {
 	case NVME_ANA_INACCESSIBLE:
 	case NVME_ANA_PERSISTENT_LOSS:
 		break;
@@ -506,8 +506,8 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req)
 		break;
         }
 
-	if (ns->bdev)
-		nvmet_bdev_set_limits(ns->bdev, id);
+	if (req->ns->bdev)
+		nvmet_bdev_set_limits(req->ns->bdev, id);
 
 	/*
 	 * We just provide a single LBA format that matches what the
@@ -521,25 +521,24 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req)
 	 * controllers, but also with any other user of the block device.
 	 */
 	id->nmic = (1 << 0);
-	id->anagrpid = cpu_to_le32(ns->anagrpid);
+	id->anagrpid = cpu_to_le32(req->ns->anagrpid);
 
-	memcpy(&id->nguid, &ns->nguid, sizeof(id->nguid));
+	memcpy(&id->nguid, &req->ns->nguid, sizeof(id->nguid));
 
-	id->lbaf[0].ds = ns->blksize_shift;
+	id->lbaf[0].ds = req->ns->blksize_shift;
 
-	if (ctrl->pi_support && nvmet_ns_has_pi(ns)) {
+	if (ctrl->pi_support && nvmet_ns_has_pi(req->ns)) {
 		id->dpc = NVME_NS_DPC_PI_FIRST | NVME_NS_DPC_PI_LAST |
 			  NVME_NS_DPC_PI_TYPE1 | NVME_NS_DPC_PI_TYPE2 |
 			  NVME_NS_DPC_PI_TYPE3;
 		id->mc = NVME_MC_EXTENDED_LBA;
-		id->dps = ns->pi_type;
+		id->dps = req->ns->pi_type;
 		id->flbas = NVME_NS_FLBAS_META_EXT;
-		id->lbaf[0].ms = cpu_to_le16(ns->metadata_size);
+		id->lbaf[0].ms = cpu_to_le16(req->ns->metadata_size);
 	}
 
-	if (ns->readonly)
+	if (req->ns->readonly)
 		id->nsattr |= (1 << 0);
-	nvmet_put_namespace(ns);
 done:
 	if (!status)
 		status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id));
-- 
2.22.1



From sagi at grimberg.me  Wed Jan 13 21:06:57 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 18:06:57 -0800
Subject: [PATCH V4 1/4] nvmet: set right status on error in id-ns handler
In-Reply-To: <20210114013354.33946-2-chaitanya.kulkarni@wdc.com>
References: <20210114013354.33946-1-chaitanya.kulkarni@wdc.com>
 <20210114013354.33946-2-chaitanya.kulkarni@wdc.com>
Message-ID: <3d1c0f3f-f303-4a5a-a2c6-72ca11ca6a5f@grimberg.me>

Reviewed-by: Sagi Grimberg <sagi at grimberg.me>


From sagi at grimberg.me  Wed Jan 13 21:07:03 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 18:07:03 -0800
Subject: [PATCH V4 2/4] nvmet: remove extra variable in smart log nsid
In-Reply-To: <20210114013354.33946-3-chaitanya.kulkarni@wdc.com>
References: <20210114013354.33946-1-chaitanya.kulkarni@wdc.com>
 <20210114013354.33946-3-chaitanya.kulkarni@wdc.com>
Message-ID: <059a1245-954a-36ad-df35-8565b81f9529@grimberg.me>

Reviewed-by: Sagi Grimberg <sagi at grimberg.me>


From sagi at grimberg.me  Wed Jan 13 21:07:11 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 18:07:11 -0800
Subject: [PATCH V4 3/4] nvmet: remove extra variable in id-desclist
In-Reply-To: <20210114013354.33946-4-chaitanya.kulkarni@wdc.com>
References: <20210114013354.33946-1-chaitanya.kulkarni@wdc.com>
 <20210114013354.33946-4-chaitanya.kulkarni@wdc.com>
Message-ID: <0ce05e4c-c89e-41d5-2f09-e531660614cd@grimberg.me>

Reviewed-by: Sagi Grimberg <sagi at grimberg.me>


From sagi at grimberg.me  Wed Jan 13 21:07:20 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 18:07:20 -0800
Subject: [PATCH V4 4/4] nvmet: remove extra variable in identify ns
In-Reply-To: <20210114013354.33946-5-chaitanya.kulkarni@wdc.com>
References: <20210114013354.33946-1-chaitanya.kulkarni@wdc.com>
 <20210114013354.33946-5-chaitanya.kulkarni@wdc.com>
Message-ID: <0d26053a-e15d-3771-f663-ea65f63423dc@grimberg.me>

Reviewed-by: Sagi Grimberg <sagi at grimberg.me>


From sagi at grimberg.me  Wed Jan 13 21:22:30 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 18:22:30 -0800
Subject: [RFC PATCH 0/2] nvmet-tcp: introduce idle poll option
In-Reply-To: <BYAPR11MB2869A106FF8E7D7FEAD30EF1E5C60@BYAPR11MB2869.namprd11.prod.outlook.com>
References: <BYAPR11MB2869A106FF8E7D7FEAD30EF1E5C60@BYAPR11MB2869.namprd11.prod.outlook.com>
Message-ID: <62cf6b4c-3b8b-db9f-f960-85efaf0896b6@grimberg.me>

Hey Mark,

On 12/14/20 5:11 PM, Wunderlich, Mark wrote:
> This RFC 2 patch series was created as an alternative solution to the previous series I submitted back on 8/27/2020 [nvmet_tcp: introduce poll groups and polling optimizations], where only the first patch in that series was accepted.  This series is greatly simplified from that previous patch series in that it does not explicitly create managed/tracked poll groups, with the io_work() function processing of a single queue preserved.  This simplified patch series relies on the accepted new queue context assignment to so_incoming_cpu to logically maintain shared processing of a logical group of queues on the same CPU core.
> 
> What this new patch pair provides is twofold. First, it introduces changes and a new nvmet-tcp module option 'idle_poll_period' that enables the kworker for a given queue to persistently get re-queued until the queue is sensed as being 'idle'.  Idle being determined as being when there is no new requests or pending backend device completions for the specified 'idle_poll_period' length of time.  By allowing this type of persistent poll behavior it is then possible to introduce the capability contained in the second patch of the set, this being the ability to have the kworker directly poll a backend NVMe device for completions instead of waiting for the NVMe device to interrupt and push out completions.
> 
> The data below shows that this new polling option, and removing of NVMe device interrupts, can have a benefit to performance.  But it is understood that this change prototype has some drawbacks, one specifically being how the nvmet-tcp module is being allowed to directly call the newly introduced block layer poll once function which can be considered a layering violation.  But in it's current state the patch series at least is a means to open discussion towards the benefits of working towards enabling such a polling model.  Is it a sound concept, but best implemented in the nvme target core layer instead?  Maybe moving away from using kworkers and having more dedicated core service tasks for logical queue groups?
> 
> The following test data was collected using the following config:
> . FIO io_uring, using HIPRI option
> . 4 FIO jobs, each directed at 3 NVMe device namespaces, each with 4 threads pinned to isolated NUMA node CPU close to NIC for total of 16 active thread connections.
> . 4K, random read I/O pattern
> . Queue Depth 32, Batch size 8
> . Initiator NIC HW queues set to 52 (number of local NUMA cores), HW queue affinity set to local NUMA cores.
> . Target NIC HW queues set to 8 , HW queue affinity set to local NUMA cores.
> . Initiator to Target connected using 1 default, 32 poll queues.
> . When testing with 'idle_poll_period' enabled, to test polling NVMe devices, the target NVMe module loaded with module option to enable 16 poll queues.
> . Patches tested and developed on linux-nvme nvme-5.10 branch.
> . All measured times in usecs unless otherwise noted.
> . Fewer target HW queues vs. number of active connections to measure the impact of virtual grouping of connection processing on shared target cores.
> 
> Baseline - patches not applied
> IOPS(k)? ?????????????? Avg Lat??????????????? 99.99???? 99.90???? 99.00???? Stdev??????????????????? Context Switch? ?????????????? Tgt. CPU Util.
> 1910???????????????????? 252.92????????????????? 685??????? 578??????? 502??????? 98.45??????????????????? ~215K?????????????????? ?????????????? 801.37
> 
> Patches applied on target - module option 'idle_poll_period' not set.
> 2152???????????????????? 223.31????????????????? 685??????? 611??????? 424??????? 92.11??????????????????? ~120K?????????????????? ?????????????? 882.14
> 
> Patches applied on target - module option 'idle_poll_period' set to 750000 usecs. (NVMe module not enabling poll queues)
> 2227???????????????????? 216.65????????????????? 627??????? 553??????? 388??????? 69.48??????????????????? ~100-400???????????? ?????????????? 934.35
> 
> Patches applied on target - module option 'idle_poll_period' set to 750000 usecs. NVMe module loaded enabling 16 poll queues.
> 2779???????????????????? 168.60????????????????? 545??????? 474??????? 375??????? 53.24??????????????????? ~100-400???????????? ?????????????? 802
> 
> This data shows that adding the new idle poll option does not impact performance when not used.  When used with the addition of direct NVMe device polling for completions, there is a nice performance benefit.
> It was noted during testing that logical grouping of queues to cores on the target can vary as a result of RSS which will or without this patch series which can vary the performance achieved, but when using the patch set with direct NVMe device polling then the logical queue grouping was more consistent and performance varied less.

So it does seem that polling the backend devices does have merit, and 
the command tracking indicator if we should poll the backend devices is
an interesting idea.

However this should something that should really be handled by nvmet
core. We could potentially add some counters to nvmet_sq and/or
nvmet_cq.

My difficulty is to understand if we can move the I/O threads from the
transport drivers to the core. Right now the I/O contexts are provided
by either the transports or the backend devices. IFF we want to explore
this (and as I said, you clearly showed it has merit), we would need to
explore if moving the I/O context and build
transport_poll/transport_wait sort of interface for this.

This can be done for tcp/rdma and loop for sure, but I'm not sure
what we can do for FC (but maybe this is possible, need to look
further).

Adding Chaitanya who looked into device polling in the past to get
his feedback if this is something interesting.


From sagi at grimberg.me  Wed Jan 13 21:29:45 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 18:29:45 -0800
Subject: [RFC PATCH 2/2] nvmet_tcp: enable polling nvme for completions
In-Reply-To: <BYAPR11MB28696A3E9DB98DE8AC271EFDE5C60@BYAPR11MB2869.namprd11.prod.outlook.com>
References: <BYAPR11MB28696A3E9DB98DE8AC271EFDE5C60@BYAPR11MB2869.namprd11.prod.outlook.com>
Message-ID: <65f7e710-a9fd-8ebb-70ad-5a6cfde4cc9e@grimberg.me>


> nvmet_tcp: enable polling nvme for completions
> 
> NVMe device queue interrupt activity can conflict with CPUs
> processing NVMe/TCP network queues.  This patch adds the ability
> to poll an NVMe device for completions, when NVMe device poll
> queues are configured.
> 
> A new non-blocking blk_poll_once() function is introduced to
> provide a one shot option to poll an individual NVMe device
> queue.
> 
> Per-queue tracking of outstanding requests to specific NVMe
> devices established to facilitate directed use of the new
> blk_poll_once() function.
> 
> These changes are viable after adding the previous patch
> that added the idle_poll_period option to io_work(). If this
> option is not enabled then use of NVMe device polling is
> bypassed.
> 
> Signed-off-by: Mark Wunderlich <mark.wunderlich at intel.com>
> ---
>   block/blk-mq.c                    |   22 +++++++++
>   drivers/nvme/target/io-cmd-bdev.c |    6 ++
>   drivers/nvme/target/nvmet.h       |    4 ++
>   drivers/nvme/target/tcp.c         |   90 ++++++++++++++++++++++++++++++++++++-
>   include/linux/blkdev.h            |    1
>   5 files changed, 120 insertions(+), 3 deletions(-)

Patches for block, nvmet core and nvmet-tcp should be split into
sub-patches.

> 
> diff --git a/block/blk-mq.c b/block/blk-mq.c
> index 55bcee5dc032..ceacf327f65e 100644
> --- a/block/blk-mq.c
> +++ b/block/blk-mq.c
> @@ -3832,6 +3832,28 @@ static bool blk_mq_poll_hybrid(struct request_queue *q,
>   	return blk_mq_poll_hybrid_sleep(q, rq);
>   }
>   
> +int blk_poll_once(struct request_queue *q)
> +{
> +	struct blk_mq_hw_ctx *hctx;
> +	int ret;
> +
> +	if (!test_bit(QUEUE_FLAG_POLL, &q->queue_flags))
> +		return 0;
> +
> +	hctx = blk_mq_map_queue_type(q, HCTX_TYPE_POLL, smp_processor_id());

This should probably be __smp_processor_id() in a preemptible context.

> +	if (!hctx) {
> +		pr_err("%s: hctx not resolved\n", __func__);
> +		return 0;
> +	}
> +
> +	hctx->poll_invoked++;
> +	ret = q->mq_ops->poll(hctx);
> +	if (ret > 0)
> +		hctx->poll_success++;
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(blk_poll_once);
> +
>   /**
>    * blk_poll - poll for IO completions
>    * @q:  the queue
> diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
> index 125dde3f410e..1d9ee8546ae1 100644
> --- a/drivers/nvme/target/io-cmd-bdev.c
> +++ b/drivers/nvme/target/io-cmd-bdev.c
> @@ -269,6 +269,12 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req)
>   	bio->bi_iter.bi_sector = sector;
>   	bio->bi_private = req;
>   	bio->bi_end_io = nvmet_bio_done;
> +	/* Set hipri flag to trigger use of poll queues */
> +	if ((req->op & REQ_HIPRI) &&
> +	    test_bit(QUEUE_FLAG_POLL, &bio->bi_disk->queue->queue_flags)) {
> +		op |= REQ_HIPRI;
> +		req->queue = bio->bi_disk->queue;
> +	}
>   	bio->bi_opf = op;
>   
>   	blk_start_plug(&plug);
> diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
> index 559a15ccc322..65900df2b45d 100644
> --- a/drivers/nvme/target/nvmet.h
> +++ b/drivers/nvme/target/nvmet.h
> @@ -341,6 +341,10 @@ struct nvmet_req {
>   	size_t			transfer_len;
>   	size_t			metadata_len;
>   
> +	/* details to support polling */
> +	struct request_queue	*queue;
> +	int			op;
> +
>   	struct nvmet_port	*port;
>   
>   	void (*execute)(struct nvmet_req *req);
> diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
> index 739d67985d93..43a0cc630bc7 100644
> --- a/drivers/nvme/target/tcp.c
> +++ b/drivers/nvme/target/tcp.c
> @@ -62,6 +62,12 @@ enum {
>   	NVMET_TCP_F_INIT_FAILED = (1 << 0),
>   };
>   
> +struct nvmet_tcp_devq {
> +	u32				pend_cnt;
> +	struct request_queue		*queue;
> +	struct list_head		entry;
> +};
> +
>   struct nvmet_tcp_cmd {
>   	struct nvmet_tcp_queue		*queue;
>   	struct nvmet_req		req;
> @@ -82,6 +88,7 @@ struct nvmet_tcp_cmd {
>   	struct kvec			*iov;
>   	u32				flags;
>   
> +	struct nvmet_tcp_devq		*devq;
>   	struct list_head		entry;
>   	struct llist_node		lentry;
>   
> @@ -142,6 +149,9 @@ struct nvmet_tcp_queue {
>   	int			idx;
>   	struct list_head	queue_list;
>   
> +	/* ref to group subsys devq entry */
> +	struct list_head	devq_list;
> +
>   	struct nvmet_tcp_cmd	connect;
>   
>   	struct page_frag_cache	pf_cache;
> @@ -237,6 +247,42 @@ static inline int queue_cpu(struct nvmet_tcp_queue *queue)
>   	return queue->sock->sk->sk_incoming_cpu;
>   }
>   
> +static int nvmet_tcp_track_queue(struct nvmet_tcp_queue *queue)
> +{
> +	struct nvmet_tcp_devq *devq;
> +	struct nvmet_req *req = &queue->cmd->req;
> +
> +	/* track only requests issued as poll requests */
> +	if (req->queue == NULL)
> +		return 0;
> +
> +	list_for_each_entry(devq, &queue->devq_list, entry) {
> +		if (devq->queue == req->queue)
> +			goto update;
> +	}
> +
> +	devq = kzalloc(sizeof(*devq), GFP_KERNEL);
> +	if (!devq)
> +		return -ENOMEM;
> +	list_add_tail(&devq->entry, &queue->devq_list);
> +	devq->queue = req->queue;
> +update:
> +	devq->pend_cnt++;
> +	queue->cmd->devq = devq;
> +	return 0;
> +}
> +
> +static void nvmet_tcp_free_dev_tracking(struct nvmet_tcp_queue *queue)
> +{
> +	struct nvmet_tcp_devq *devq;
> +
> +	while ((devq = list_first_entry_or_null(
> +			&queue->devq_list, struct nvmet_tcp_devq, entry))) {
> +		list_del_init(&devq->entry);
> +		kfree(devq);
> +	}
> +}
> +
>   static inline u8 nvmet_tcp_hdgst_len(struct nvmet_tcp_queue *queue)
>   {
>   	return queue->hdr_digest ? NVME_TCP_DIGEST_LENGTH : 0;
> @@ -479,6 +525,25 @@ static void nvmet_setup_response_pdu(struct nvmet_tcp_cmd *cmd)
>   	}
>   }
>   
> +static inline void nvmet_tcp_poll_init(struct nvmet_req *req)
> +{
> +	req->queue = NULL;
> +	if (idle_poll_period)
> +		req->op |= REQ_HIPRI;
> +	else
> +		req->op = 0;
> +}

All of this patch really exemplifies why none of this should live
in nvme-tcp.

All of this management, tracking, and decisions should live in
nvmet core. But as I said, I'm not convinced that this is an easy
change because it fundamentally changes the target architecture (not
saying we shouldn't do this, but it is a rather intrusive change).

Would be good to hear what others think on this. I do think that all
transports would benefit from backend device polling (despite
demonstrated on nvme-tcp).


From lengchao at huawei.com  Wed Jan 13 21:47:56 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 14 Jan 2021 10:47:56 +0800
Subject: [PATCH V2 2/2] nvme: retry commands based on ACRE result
In-Reply-To: <20210113143538.554-3-minwoo.im.dev@gmail.com>
References: <20210113143538.554-1-minwoo.im.dev@gmail.com>
 <20210113143538.554-3-minwoo.im.dev@gmail.com>
Message-ID: <b122f482-cb73-67ff-1a30-053c1e8c9c18@huawei.com>



On 2021/1/13 22:35, Minwoo Im wrote:
> Introduce acre flag for Advanced Command Retry Enable to controller
> instance to decide whether to retry or not in error cases.  This flag is
> set if Set Features for Host Behavior Support with ACRE bit set is
> successfully done during reset_work.
> 
> This patch also fixes nvme_decide_disposition() because all the nvme
> requests are initialized with REQ_FAILFAST_DRIVER to req->cmd_flags so
> that blk_noretry_request(req) is always true.  Check ctrl->acre first
> and if it's not host path error, then it will be retried.
> 
> Cc: Chao Leng <lengchao at huawei.com>
> Signed-off-by: Minwoo Im <minwoo.im.dev at gmail.com>
> ---
>   drivers/nvme/host/core.c | 16 ++++++++++++++--
>   drivers/nvme/host/nvme.h |  1 +
>   2 files changed, 15 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
> index a8cee380b3c0..391bb2d08d0f 100644
> --- a/drivers/nvme/host/core.c
> +++ b/drivers/nvme/host/core.c
> @@ -303,8 +303,7 @@ static inline enum nvme_disposition nvme_decide_disposition(struct request *req)
>   	if (likely(nvme_req(req)->status == 0))
>   		return COMPLETE;
>   
> -	if (blk_noretry_request(req) ||
> -	    (nvme_req(req)->status & NVME_SC_DNR) ||
> +	if ((nvme_req(req)->status & NVME_SC_DNR) ||
>   	    nvme_req(req)->retries >= nvme_max_retries)
>   		return COMPLETE;
>   
> @@ -317,6 +316,13 @@ static inline enum nvme_disposition nvme_decide_disposition(struct request *req)
>   			return COMPLETE;
>   	}
>   
> +	if (nvme_req(req)->ctrl->acre) {
> +		if (!nvme_is_path_error(nvme_req(req)->status) &&
> +				!blk_queue_dying(req->q))
> +			return RETRY;
> +	} else if (blk_noretry_request(req))
> +		return COMPLETE;
If acre is true and nvme_req(req)->status is nvme path error and
blk_noretry_request(req) is true, we need return complete for REQ_FAILFAST_XX.
Otherwise, connection process may takes long time in abnormal scenarios.
We can do like this:

+    if (nvme_req(req)->ctrl->acre &&
+        !nvme_is_path_error(nvme_req(req)->status) &&
+        !blk_queue_dying(req->q))
+        return RETRY;
+
+    if (blk_noretry_request(req))
+        return COMPLETE;
> +
>   	return RETRY;
>   }
>   
> @@ -2498,6 +2504,8 @@ static int nvme_configure_acre(struct nvme_ctrl *ctrl)
>   	struct nvme_feat_host_behavior *host;
>   	int ret;
>   
> +	ctrl->acre = false;
> +
>   	/* Don't bother enabling the feature if retry delay is not reported */
>   	if (!ctrl->crdt[0] && !ctrl->crdt[1] && !ctrl->crdt[2])
>   		return 0;
> @@ -2509,6 +2517,10 @@ static int nvme_configure_acre(struct nvme_ctrl *ctrl)
>   	host->acre = NVME_ENABLE_ACRE;
>   	ret = nvme_set_features(ctrl, NVME_FEAT_HOST_BEHAVIOR, 0,
>   				host, sizeof(*host), NULL);
> +
> +	if (!ret)
> +		ctrl->acre = true;
> +
>   	kfree(host);
>   	return ret;
>   }
> diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
> index 88a6b97247f5..db8b45e8ffde 100644
> --- a/drivers/nvme/host/nvme.h
> +++ b/drivers/nvme/host/nvme.h
> @@ -270,6 +270,7 @@ struct nvme_ctrl {
>   #ifdef CONFIG_BLK_DEV_ZONED
>   	u32 max_zone_append;
>   #endif
> +	bool acre;
>   	u16 crdt[3];
>   	u16 oncs;
>   	u16 oacs;
> 


From sagi at grimberg.me  Wed Jan 13 22:09:18 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 19:09:18 -0800
Subject: [PATCH] nvme-core: update NS Attr Changed AEN handling for ANA
 group
In-Reply-To: <20201210133418.GA3645@redsun51.ssa.fujisawa.hgst.com>
References: <20201209155321.GA31729@redsun51.ssa.fujisawa.hgst.com>
 <b9c9e5f9-a447-2a2e-b687-304dd8f3d2b2@suse.de>
 <20201209161911.GA31836@redsun51.ssa.fujisawa.hgst.com>
 <66bad47c-0cd3-8461-3629-146778f15059@suse.de>
 <20201209173936.GA31971@redsun51.ssa.fujisawa.hgst.com>
 <20201209174718.GA19512@lst.de>
 <DM5PR0601MB3624722C4C00B5A7EDB7E6A0F1CC0@DM5PR0601MB3624.namprd06.prod.outlook.com>
 <20201209213437.GA3682670@dhcp-10-100-145-180.wdc.com>
 <20201210085111.GA15999@lst.de>
 <baa8c2e6-1376-1cad-4c84-1129bd80d4ca@suse.de>
 <20201210133418.GA3645@redsun51.ssa.fujisawa.hgst.com>
Message-ID: <eb84db43-5e63-19b4-cdb9-53f52d1c45e8@grimberg.me>

Hey all,

Joining late to the discussion, ramping up on an old old backlog...

>>> On Wed, Dec 09, 2020 at 01:34:37PM -0800, Keith Busch wrote:
>>>> Linux hosts currently want an ANA AEN anytime the host needs to refresh
>>>> the ANA log. That includes any condition that adds groups that didn't
>>>> exist from the host's previous reading.
>>>>
>>>> If the Namespace Attach occurs to an ANA group the host already knows
>>>> about, then you don't need to send an ANA AEN because there's nothing
>>>> new in the log that the host requires. You just need to send the NS
>>>> Notify AEN.
>>>>
>>>> But if a side effect of attaching a namespace results in a new ANA group
>>>> becoming visible to the host, then that group creation is considered a
>>>> separate event, so the host wants both AENs. I believe this is where
>>>> Christoph is trying to steer the interpretation and the text.
>>>
>>> Exactly.  Although as Hannes pointed out, this language:
>>>
>>>     If, for an ANA Group, there are no namespaces attached to the
>>>     controller processing the command, then no ANA Group Descriptor is
>>>     returned for that ANA Group (i.e., an ANA Group Descriptor is returned
>>>     only if that ANA Group contains namespaces that are attached to the
>>>     controller processing the command.
>>>
>>> creates a bit of a chicken an egg problem in that case of a newly
>>> attached namespace that is the first one referencing an ANA group.

FWIW, the subsystems I'm familiar with are sending both events in this
case and the interpretation of this paragraph was that although the ANA
group existed since day-0, the host was never informed about it, so
just like lots of other internal resources, it doesn't exist from an
interface perspective.

The alternative would have been to tell the host about every ANA group
that the subsystem is managing, which could be a very large number and
just creates a churn of completely useless huge log pages.

>> Yes, this was what I tried to outline.
>>
>> Personally I don't mind whether the controller is required to send an ANA
>> change AEN together with the NS change AEN.
>> Requiring both will pose an ordering issue (as on fabrics we can't control
>> the completion ordering), so effectively we'll have to implement handling
>> for AENs arriving in any order.
> 
> I was thinking more about this, and it's actually not a problem based on
> how the controller is allowed to send AEN completions:
> 
>    When the controller posts a completion queue entry for an outstanding
>    Asynchronous Event Request command and thus reports an asynchronous
>    event, subsequent events of that event type are automatically masked by
>    the controller until the host clears that event.
> 
> These are both "Notice" event types, so the controller is not allowed to
> send both at the same time. The host must acknowledge the first before
> the second can be seen, so we can enforce a deterministic sequence.

Well that is easy today because there is only one aen at a time...

> And while it may make sense if the first event seen is the ANA one
> before the NS, it doesn't look like Linux cares if we observe them the
> other way around. The only thing the driver needs to do is synchronize
> the work queues for each event.

Yes, the order doesn't matter and we should keep it that way...

>> But I'm also fine with just getting one AEN; the patch will solve that
>> situation just fine.
> 
> I'm also okay with that patch, too.

I would actually be in favor of this patch, would be nice to skip
sending duplicate events for this.


From kbusch at kernel.org  Wed Jan 13 22:11:02 2021
From: kbusch at kernel.org (Keith Busch)
Date: Wed, 13 Jan 2021 19:11:02 -0800
Subject: [PATCH V2 2/2] nvme: retry commands based on ACRE result
In-Reply-To: <20210113143538.554-3-minwoo.im.dev@gmail.com>
References: <20210113143538.554-1-minwoo.im.dev@gmail.com>
 <20210113143538.554-3-minwoo.im.dev@gmail.com>
Message-ID: <20210114031102.GA1509941@dhcp-10-100-145-180.wdc.com>

On Wed, Jan 13, 2021 at 11:35:38PM +0900, Minwoo Im wrote:
> @@ -317,6 +316,13 @@ static inline enum nvme_disposition nvme_decide_disposition(struct request *req)
>  			return COMPLETE;
>  	}
>  
> +	if (nvme_req(req)->ctrl->acre) {
> +		if (!nvme_is_path_error(nvme_req(req)->status) &&
> +				!blk_queue_dying(req->q))
> +			return RETRY;
> +	} else if (blk_noretry_request(req))
> +		return COMPLETE;
> +
>  	return RETRY;
>  }

This is returning RETRY for path related errors when blk_notry_request()
is true. That will deadlock initialization on a command timeout. The
check should be something like this:

	if (nvme_req(req)->ctrl->acre &&
	    !nvme_is_path_error(nvme_req(req)->status) &&
	    !blk_queue_dying(req->q))
		return RETRY;
	else if (blk_noretry_request(req))
		return COMPLETE;




From sagi at grimberg.me  Wed Jan 13 22:13:10 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 13 Jan 2021 19:13:10 -0800
Subject: [PATCH] nvme: retrigger ANA log update if group descriptor isn't
 found
In-Reply-To: <20201205152901.56665-1-hare@suse.de>
References: <20201205152901.56665-1-hare@suse.de>
Message-ID: <cbfc78e1-87be-cc09-9b8d-44bf0659eb26@grimberg.me>


> If ANA is enabled but no ANA group descriptor is found when creating
> a new namespace the ANA log is most likely out of date, so trigger
> a re-read. The namespace will be tagged with the NS_ANA_PENDING flag
> to exclude it from path selection until the ANA log has been re-read.
> 
> Reported-by: Martin George <marting at netapp.com>
> Signed-off-by: Hannes Reinecke <hare at suse.de>
> ---
>   drivers/nvme/host/multipath.c | 4 ++++
>   1 file changed, 4 insertions(+)
> 
> diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
> index 74896be40c17..ee4a42dc99a0 100644
> --- a/drivers/nvme/host/multipath.c
> +++ b/drivers/nvme/host/multipath.c
> @@ -667,6 +667,10 @@ void nvme_mpath_add_disk(struct nvme_ns *ns, struct nvme_id_ns *id)
>   		if (desc.state) {
>   			/* found the group desc: update */
>   			nvme_update_ns_ana_state(&desc, ns);
> +		} else {
> +			/* group desc not found: trigger a re-read */
> +			set_bit(NVME_NS_ANA_PENDING, &ns->flags);
> +			queue_work(nvme_wq, &ns->ctrl->ana_work);

btw, I just commented on the original thread, but I do like this
one better.

Reviewed-by: Sagi Grimberg <sagi at grimberg.me>


From minwoo.im.dev at gmail.com  Wed Jan 13 22:27:21 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Thu, 14 Jan 2021 12:27:21 +0900
Subject: [PATCH V2 2/2] nvme: retry commands based on ACRE result
In-Reply-To: <b122f482-cb73-67ff-1a30-053c1e8c9c18@huawei.com>
References: <20210113143538.554-1-minwoo.im.dev@gmail.com>
 <20210113143538.554-3-minwoo.im.dev@gmail.com>
 <b122f482-cb73-67ff-1a30-053c1e8c9c18@huawei.com>
Message-ID: <20210114032721.GA5817@localhost.localdomain>

Hello,

> If acre is true and nvme_req(req)->status is nvme path error and
> blk_noretry_request(req) is true, we need return complete for REQ_FAILFAST_XX.
> Otherwise, connection process may takes long time in abnormal scenarios.
> We can do like this:
> 
> +    if (nvme_req(req)->ctrl->acre &&
> +        !nvme_is_path_error(nvme_req(req)->status) &&
> +        !blk_queue_dying(req->q))
> +        return RETRY;
> +
> +    if (blk_noretry_request(req))
> +        return COMPLETE;

Ah.. You're right.. I really appreciate for your review!
I will prepare the next patches.

Thank you!


From minwoo.im.dev at gmail.com  Wed Jan 13 22:28:11 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Thu, 14 Jan 2021 12:28:11 +0900
Subject: [PATCH V2 2/2] nvme: retry commands based on ACRE result
In-Reply-To: <20210114031102.GA1509941@dhcp-10-100-145-180.wdc.com>
References: <20210113143538.554-1-minwoo.im.dev@gmail.com>
 <20210113143538.554-3-minwoo.im.dev@gmail.com>
 <20210114031102.GA1509941@dhcp-10-100-145-180.wdc.com>
Message-ID: <20210114032811.GB5817@localhost.localdomain>

Hello Keith,

On 21-01-13 19:11:02, Keith Busch wrote:
> On Wed, Jan 13, 2021 at 11:35:38PM +0900, Minwoo Im wrote:
> > @@ -317,6 +316,13 @@ static inline enum nvme_disposition nvme_decide_disposition(struct request *req)
> >  			return COMPLETE;
> >  	}
> >  
> > +	if (nvme_req(req)->ctrl->acre) {
> > +		if (!nvme_is_path_error(nvme_req(req)->status) &&
> > +				!blk_queue_dying(req->q))
> > +			return RETRY;
> > +	} else if (blk_noretry_request(req))
> > +		return COMPLETE;
> > +
> >  	return RETRY;
> >  }
> 
> This is returning RETRY for path related errors when blk_notry_request()
> is true. That will deadlock initialization on a command timeout. The
> check should be something like this:
> 
> 	if (nvme_req(req)->ctrl->acre &&
> 	    !nvme_is_path_error(nvme_req(req)->status) &&
> 	    !blk_queue_dying(req->q))
> 		return RETRY;
> 	else if (blk_noretry_request(req))
> 		return COMPLETE;
> 
> 

Thank you for chatching this!  As Chao pointed it out, I will prepare
the next version of this patch.  I really appreciate it.

Thanks!


From Chaitanya.Kulkarni at wdc.com  Wed Jan 13 22:34:36 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Thu, 14 Jan 2021 03:34:36 +0000
Subject: [PATCH V4 0/4] nvmet: admin-cmd related cleanups and a fix
References: <20210114013354.33946-1-chaitanya.kulkarni@wdc.com>
Message-ID: <BYAPR04MB4965B8DDB144D6B6B09A0F8386A80@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/13/21 5:34 PM, Chaitanya Kulkarni wrote:
> Hi,
>
> There are three functions where local variable ns is used instead of
> using req->ns which leads to duplicate nvmet_put_namespace() calls.
> We can just use req->ns and not the local variable to avoid duplicate
> calls.
>
> The first patch sets the right error status code when namespace is not
> found in nvmet_execute_identify_ns().
>
> I've tested this series with nvme blktests, all the testcases are
> passing.
>
> -ck
>
Thanks for the reviewed-by tags Sagi.


From dsahern at gmail.com  Wed Jan 13 23:47:40 2021
From: dsahern at gmail.com (David Ahern)
Date: Wed, 13 Jan 2021 21:47:40 -0700
Subject: [PATCH v1 net-next 00/15] nvme-tcp receive offloads
In-Reply-To: <69f9a7c3-e2ab-454a-2713-2e9c9dea4e47@grimberg.me>
References: <20201207210649.19194-1-borisp@mellanox.com>
 <69f9a7c3-e2ab-454a-2713-2e9c9dea4e47@grimberg.me>
Message-ID: <967ae867-42c9-731d-9cb1-2c81fcc1ef77@gmail.com>

On 1/13/21 6:27 PM, Sagi Grimberg wrote:
>> Changes since RFC v1:
>> =========================================
>> * Split mlx5 driver patches to several commits
>> * Fix nvme-tcp handling of recovery flows. In particular, move queue
>> offlaod
>> ?? init/teardown to the start/stop functions.
> 
> I'm assuming that you tested controller resets and network hiccups
> during traffic right?

I had questions on this part as well -- e.g., what happens on a TCP
retry? packets arrive, sgl filled for the command id, but packet is
dropped in the stack (e.g., enqueue backlog is filled, so packet gets
dropped)


From lifeng1519 at gmail.com  Thu Jan 14 00:17:03 2021
From: lifeng1519 at gmail.com (Feng Li)
Date: Thu, 14 Jan 2021 13:17:03 +0800
Subject: [PATCH] nvme: reject the ns when the block size is smaller than a
 sector
In-Reply-To: <87698545-de26-c0ca-01e9-4dc2ddcacc80@grimberg.me>
References: <20210113160621.98615-1-fengli@smartx.com>
 <SN4PR0401MB35985C08E5FFCDF0F5817A9D9BA90@SN4PR0401MB3598.namprd04.prod.outlook.com>
 <87698545-de26-c0ca-01e9-4dc2ddcacc80@grimberg.me>
Message-ID: <CAEK8JBC8SzabKnG_K-axf-7Fbvc6Ng57gh=5CJjfd8U1uqjvRQ@mail.gmail.com>

Sagi Grimberg <sagi at grimberg.me> ?2021?1?14??? ??6:13???
>
>
> >> The nvme spec(1.4a, figure 248) says:
> >> "A value smaller than 9 (i.e., 512 bytes) is not supported."
> >>
> >> Signed-off-by: Li Feng <fengli at smartx.com>
> >> ---
> >>   drivers/nvme/host/core.c | 6 ++++++
> >>   1 file changed, 6 insertions(+)
> >>
> >> diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
> >> index f320273fc672..1f02e6e49a05 100644
> >> --- a/drivers/nvme/host/core.c
> >> +++ b/drivers/nvme/host/core.c
> >> @@ -2161,6 +2161,12 @@ static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_id_ns *id)
> >>
> >>      blk_mq_freeze_queue(ns->disk->queue);
> >>      ns->lba_shift = id->lbaf[lbaf].ds;
> >> +    if (ns->lba_shift < 9) {
> >> +            pr_warn("%s: bad lba_shift(%d)\n", ns->disk->disk_name, ns->lba_shift);
> >> +            ret = -1;
>
> Meaningful errno would be useful. Also better to use dev_warn
>
> >> +            goto out_unfreeze;
> >> +    }
> >> +
> >>      nvme_set_queue_limits(ns->ctrl, ns->queue);
> >>
> >>      if (ns->head->ids.csi == NVME_CSI_ZNS) {
> >>
> >
> >
> > But this only catches a physical block size < 512 for NVMe, not any other block device.
> >
> > Please fix it for the general case in blk_queue_physical_block_size().
>
> We actually call that later and would probably be better to check here..
Thanks for your comments.

The prototype is:
void blk_queue_logical_block_size(struct request_queue *, unsigned int);

So change it to:
bool blk_queue_logical_block_size(struct request_queue *, unsigned int);

And check all callers of this function, right?


From lengchao at huawei.com  Thu Jan 14 01:50:02 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 14 Jan 2021 14:50:02 +0800
Subject: [PATCH v2 0/6] avoid repeated request completion and IO error
In-Reply-To: <879d04a5-c52e-4d21-5003-d369ab5cdaee@grimberg.me>
References: <20210107033149.15701-1-lengchao@huawei.com>
 <879d04a5-c52e-4d21-5003-d369ab5cdaee@grimberg.me>
Message-ID: <3a8426ea-1488-b7c7-630e-162e61270190@huawei.com>



On 2021/1/14 8:15, Sagi Grimberg wrote:
>> First avoid repeated request completion for nvmf_fail_nonready_command.
>> Second avoid IO error and repeated request completion for queue_rq.
> 
> Maybe this is me chiming in v2, but what is this fixing? what
> is the bug you are seeing?The bug is crash and io error in two scenarios.
First inject request time out, crash happens due to request double
completion, the probability is very low. The reason: we will do error
recovery for request time out. When error recovery, new request will
be completed by nvmf_fail_nonready_command in queue_rq, the state of
the request will be changed to MQ_RQ_IN_FLIGHT, the request is freed
asynchronously in nvme_submit_user_cmd, nvme_submit_user_cmd may
run after cancel request(the state of the request is MQ_RQ_IN_FLIGHT)
in error recovery. The request will be double completion.

Second use two HBAs for nvme native multipath, and then inject one HBA
fault, io error happens and a low probability crash happens. The reason
of io error is the blk_status_t of queue_rq is BLK_STS_IOERR, blk-mq
call blk_mq_end_request to complete the request. We expect the request
fail over to normal HBA, but the request is directly completed with
BLK_STS_IOERR. The reason of crash is similar to the first scenario.


From lengchao at huawei.com  Thu Jan 14 01:50:36 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 14 Jan 2021 14:50:36 +0800
Subject: [PATCH v2 1/6] blk-mq: introduce blk_mq_set_request_complete
In-Reply-To: <6ce3e173-4ac3-e84d-88ca-76057a8d8e1e@grimberg.me>
References: <20210107033149.15701-1-lengchao@huawei.com>
 <20210107033149.15701-2-lengchao@huawei.com>
 <6ce3e173-4ac3-e84d-88ca-76057a8d8e1e@grimberg.me>
Message-ID: <5868f270-9fda-be39-808d-929e270f52dc@huawei.com>



On 2021/1/14 8:17, Sagi Grimberg wrote:
> 
>> In some scenarios, nvme need setting the state of request to
>> MQ_RQ_COMPLETE. So add an inline function blk_mq_set_request_complete.
>> For details, see the subsequent patches.
> 
> Its kinda difficult to understand the meaning of all of this...
> the cover letter tells us nothing, and patches 1/2 also tells us
> to see subsequent patches.
> 
> This is saved in the git change log history, so please try
> describe what it is you are going with this, even if there are
> overlaps between patches.
ok, thanks for your suggest.
> .


From lengchao at huawei.com  Thu Jan 14 01:55:21 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 14 Jan 2021 14:55:21 +0800
Subject: [PATCH v2 4/6] nvme-rdma: avoid IO error and repeated request
 completion
In-Reply-To: <07e41b4f-914a-11e8-5638-e2d6408feb3f@grimberg.me>
References: <20210107033149.15701-1-lengchao@huawei.com>
 <20210107033149.15701-5-lengchao@huawei.com>
 <07e41b4f-914a-11e8-5638-e2d6408feb3f@grimberg.me>
Message-ID: <7b12be41-0fcd-5a22-0e01-8cd4ac9cde5b@huawei.com>



On 2021/1/14 8:19, Sagi Grimberg wrote:
> 
>> When a request is queued failed, blk_status_t is directly returned
>> to the blk-mq. If blk_status_t is not BLK_STS_RESOURCE,
>> BLK_STS_DEV_RESOURCE, BLK_STS_ZONE_RESOURCE, blk-mq call
>> blk_mq_end_request to complete the request with BLK_STS_IOERR.
>> In two scenarios, the request should be retried and may succeed.
>> First, if work with nvme multipath, the request may be retried
>> successfully in another path, because the error is probably related to
>> the path. Second, if work without multipath software, the request may
>> be retried successfully after error recovery.
>> If the request is complete with BLK_STS_IOERR in blk_mq_dispatch_rq_list.
>> The state of request may be changed to MQ_RQ_IN_FLIGHT. If free the
>> request asynchronously such as in nvme_submit_user_cmd, in extreme
>> scenario the request will be repeated freed in tear down.
>> If a non-resource error occurs in queue_rq, should directly call
>> nvme_complete_rq to complete request and set the state of request to
>> MQ_RQ_COMPLETE. nvme_complete_rq will decide to retry, fail over or end
>> the request.
>>
>> Signed-off-by: Chao Leng <lengchao at huawei.com>
>> ---
>> ? drivers/nvme/host/rdma.c | 2 +-
>> ? 1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
>> index df9f6f4549f1..4a89bf44ecdc 100644
>> --- a/drivers/nvme/host/rdma.c
>> +++ b/drivers/nvme/host/rdma.c
>> @@ -2093,7 +2093,7 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
>> ? unmap_qe:
>> ????? ib_dma_unmap_single(dev, req->sqe.dma, sizeof(struct nvme_command),
>> ????????????????? DMA_TO_DEVICE);
>> -??? return ret;
>> +??? return nvme_try_complete_failed_req(rq, ret);
> 
> I don't understand this. There are errors that may not be related to
> anything that is pathing related (sw bug, memory leak, mapping error,
> etc, etc) why should we return this one-shot error?
Although fail over retry is not required, if we return the error to
blk-mq, a low probability crash may happen. because blk-mq do not set
the state of request to MQ_RQ_COMPLETE before complete the request,
the request may be freed asynchronously such as in nvme_submit_user_cmd.
If race with error recovery, request double completion may happens.

So we can not return the error to blk-mq if the blk_status_t is not
BLK_STS_RESOURCE, BLK_STS_DEV_RESOURCE, BLK_STS_ZONE_RESOURCE.
> .


From lengchao at huawei.com  Thu Jan 14 01:57:38 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 14 Jan 2021 14:57:38 +0800
Subject: [PATCH] nvme-rdma: avoid repeated request completion for
 concurrent nvme_rdma_timeout
In-Reply-To: <002e7d37-433c-f8fa-f460-bfb2447d6bc0@grimberg.me>
References: <20210106063635.7452-1-lengchao@huawei.com>
 <002e7d37-433c-f8fa-f460-bfb2447d6bc0@grimberg.me>
Message-ID: <5129b717-1f4e-f7ab-640c-7f84ae7eb966@huawei.com>



On 2021/1/14 9:11, Sagi Grimberg wrote:
> 
> On 1/5/21 10:36 PM, Chao Leng wrote:
>> A crash happens when inject completing request long time(nearly 30s).
>> Each name space has a request queue, when inject completing request long
>> time, multi request queues may has time out requests at the same time,
>> nvme_rdma_timeout will execute concurrently. Multi requests in different
>> request queues may be queued in the same rdma queue, multi
>> nvme_rdma_timeout may call nvme_rdma_stop_queue at the same time.
>> The first nvme_rdma_timeout will clear NVME_RDMA_Q_LIVE and continue
>> stopping the rdma queue(drain qp), but the others check NVME_RDMA_Q_LIVE
>> is already cleared, and then directly complete the requests, but the
>> rdma queue may be not stopped and the request may be already completed
>> in qp and wait treated, the request will be repeated completed.
>> Add a multex lock to serialize nvme_rdma_stop_queue.
> 
> This looks reasonable to me,
> 
> Mind sending one for nvme-tcp as well?
ok, I will send patch v2 latter.
> 
>>
>> Signed-off-by: Chao Leng <lengchao at huawei.com>
>> ---
>> ? drivers/nvme/host/rdma.c | 15 +++++++++++----
>> ? 1 file changed, 11 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
>> index df9f6f4549f1..d5c66e3eeb4a 100644
>> --- a/drivers/nvme/host/rdma.c
>> +++ b/drivers/nvme/host/rdma.c
>> @@ -97,6 +97,7 @@ struct nvme_rdma_queue {
>> ????? struct completion??? cm_done;
>> ????? bool??????????? pi_support;
>> ????? int??????????? cq_size;
>> +??? struct mutex??????? queue_lock;
>> ? };
>> ? struct nvme_rdma_ctrl {
>> @@ -579,6 +580,7 @@ static int nvme_rdma_alloc_queue(struct nvme_rdma_ctrl *ctrl,
>> ????? int ret;
>> ????? queue = &ctrl->queues[idx];
>> +??? mutex_init(&queue->queue_lock);
>> ????? queue->ctrl = ctrl;
>> ????? if (idx && ctrl->ctrl.max_integrity_segments)
>> ????????? queue->pi_support = true;
>> @@ -598,7 +600,8 @@ static int nvme_rdma_alloc_queue(struct nvme_rdma_ctrl *ctrl,
>> ????? if (IS_ERR(queue->cm_id)) {
>> ????????? dev_info(ctrl->ctrl.device,
>> ????????????? "failed to create CM ID: %ld\n", PTR_ERR(queue->cm_id));
>> -??????? return PTR_ERR(queue->cm_id);
>> +??????? ret = PTR_ERR(queue->cm_id);
>> +??????? goto out_destroy_mutex;
>> ????? }
>> ????? if (ctrl->ctrl.opts->mask & NVMF_OPT_HOST_TRADDR)
>> @@ -628,6 +631,8 @@ static int nvme_rdma_alloc_queue(struct nvme_rdma_ctrl *ctrl,
>> ? out_destroy_cm_id:
>> ????? rdma_destroy_id(queue->cm_id);
>> ????? nvme_rdma_destroy_queue_ib(queue);
>> +out_destroy_mutex:
>> +??? mutex_destroy(&queue->queue_lock);
>> ????? return ret;
>> ? }
>> @@ -639,9 +644,10 @@ static void __nvme_rdma_stop_queue(struct nvme_rdma_queue *queue)
>> ? static void nvme_rdma_stop_queue(struct nvme_rdma_queue *queue)
>> ? {
>> -??? if (!test_and_clear_bit(NVME_RDMA_Q_LIVE, &queue->flags))
>> -??????? return;
>> -??? __nvme_rdma_stop_queue(queue);
>> +??? mutex_lock(&queue->queue_lock);
>> +??? if (test_and_clear_bit(NVME_RDMA_Q_LIVE, &queue->flags))
>> +??????? __nvme_rdma_stop_queue(queue);
>> +??? mutex_unlock(&queue->queue_lock);
>> ? }
>> ? static void nvme_rdma_free_queue(struct nvme_rdma_queue *queue)
>> @@ -649,6 +655,7 @@ static void nvme_rdma_free_queue(struct nvme_rdma_queue *queue)
>> ????? if (!test_and_clear_bit(NVME_RDMA_Q_ALLOCATED, &queue->flags))
>> ????????? return;
>> +??? mutex_destroy(&queue->queue_lock);
>> ????? nvme_rdma_destroy_queue_ib(queue);
>> ????? rdma_destroy_id(queue->cm_id);
>> ? }
>>
> .


From lengchao at huawei.com  Thu Jan 14 01:58:10 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 14 Jan 2021 14:58:10 +0800
Subject: [PATCH] nvme-rdma: avoid repeated request completion for
 concurrent nvme_rdma_timeout
In-Reply-To: <8a5b4b58-98be-4da1-a769-dc173d2a3be0@grimberg.me>
References: <20210106063635.7452-1-lengchao@huawei.com>
 <002e7d37-433c-f8fa-f460-bfb2447d6bc0@grimberg.me>
 <8a5b4b58-98be-4da1-a769-dc173d2a3be0@grimberg.me>
Message-ID: <39b076de-2fff-418f-0938-64a0415ccff1@huawei.com>



On 2021/1/14 9:15, Sagi Grimberg wrote:
> 
>> On 1/5/21 10:36 PM, Chao Leng wrote:
>>> A crash happens when inject completing request long time(nearly 30s).
>>> Each name space has a request queue, when inject completing request long
>>> time, multi request queues may has time out requests at the same time,
>>> nvme_rdma_timeout will execute concurrently. Multi requests in different
>>> request queues may be queued in the same rdma queue, multi
>>> nvme_rdma_timeout may call nvme_rdma_stop_queue at the same time.
>>> The first nvme_rdma_timeout will clear NVME_RDMA_Q_LIVE and continue
>>> stopping the rdma queue(drain qp), but the others check NVME_RDMA_Q_LIVE
>>> is already cleared, and then directly complete the requests, but the
>>> rdma queue may be not stopped and the request may be already completed
>>> in qp and wait treated, the request will be repeated completed.
>>> Add a multex lock to serialize nvme_rdma_stop_queue.
>>
>> This looks reasonable to me,
>>
>> Mind sending one for nvme-tcp as well?
> 
> BTW, I'm assuming you mean use-after-free or double completion when you
> are referring to repeated completions? I think it would be easier to
> understand if you just say that completing request before the qp is
> fully drained may lead to a use-after-free condition.
ok, thanks for your suggestion.
> .


From hch at lst.de  Thu Jan 14 02:20:15 2021
From: hch at lst.de (Christoph Hellwig)
Date: Thu, 14 Jan 2021 08:20:15 +0100
Subject: [PATCH] nvme-tcp: Fix warning with CONFIG_DEBUG_PREEMPT
In-Reply-To: <20210113220304.1615735-1-sagi@grimberg.me>
References: <20210113220304.1615735-1-sagi@grimberg.me>
Message-ID: <20210114072015.GA498@lst.de>

Applied to nvme-5.11.


From hch at lst.de  Thu Jan 14 02:22:54 2021
From: hch at lst.de (Christoph Hellwig)
Date: Thu, 14 Jan 2021 08:22:54 +0100
Subject: [PATCH 1/3] nvme: support command retry delay for admin command
In-Reply-To: <20210112080653.GB24949@lst.de>
References: <20210108144659.7126-1-minwoo.im.dev@gmail.com>
 <20210108144659.7126-2-minwoo.im.dev@gmail.com>
 <20210112080653.GB24949@lst.de>
Message-ID: <20210114072254.GA517@lst.de>

On Tue, Jan 12, 2021 at 09:06:53AM +0100, Christoph Hellwig wrote:
> Except for the little wording issue this looks good to me.  I'll pick it
> up for nvme-5.11 and will fix up the commit log.

Given that we never retry admin command right now I've moved this off 
nvme-5.11 into the pending queue.


From hch at lst.de  Thu Jan 14 02:23:10 2021
From: hch at lst.de (Christoph Hellwig)
Date: Thu, 14 Jan 2021 08:23:10 +0100
Subject: [PATCH v2] nvme-tcp: fix possible data corruption with bio merges
In-Reply-To: <20210113215657.1613817-1-sagi@grimberg.me>
References: <20210113215657.1613817-1-sagi@grimberg.me>
Message-ID: <20210114072310.GA581@lst.de>

Applied to nvme-5.11.


From hch at lst.de  Thu Jan 14 02:26:46 2021
From: hch at lst.de (Christoph Hellwig)
Date: Thu, 14 Jan 2021 08:26:46 +0100
Subject: [PATCH] nvme: don't intialize hwmon for discovery controllers
In-Reply-To: <20210114000022.1641939-1-sagi@grimberg.me>
References: <20210114000022.1641939-1-sagi@grimberg.me>
Message-ID: <20210114072646.GA670@lst.de>

Applied to nvme-5.11.


From lengchao at huawei.com  Thu Jan 14 04:09:24 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 14 Jan 2021 17:09:24 +0800
Subject: [PATCH v2 0/2] avoid request double completion for concurrent
 nvme_rdma(tcp)_timeout
Message-ID: <20210114090926.12109-1-lengchao@huawei.com>

Concurrent nvme_rdma(tcp)_timeout may cause: complete request
before the qp is fully drained(the io work is completely canceled) may
lead to a use-after-free condition.
The patch sets fix it.

Chao Leng (2):
  nvme-rdma: avoid request double completion for concurrent
    nvme_rdma_timeout
  nvme-tcp: avoid request double completion for concurrent
    nvme_tcp_timeout

 drivers/nvme/host/rdma.c | 15 +++++++++++----
 drivers/nvme/host/tcp.c  | 14 ++++++++++----
 2 files changed, 21 insertions(+), 8 deletions(-)

-- 
2.16.4



From lengchao at huawei.com  Thu Jan 14 04:09:25 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 14 Jan 2021 17:09:25 +0800
Subject: [PATCH v2 1/2] nvme-rdma: avoid request double completion for
 concurrent nvme_rdma_timeout
In-Reply-To: <20210114090926.12109-1-lengchao@huawei.com>
References: <20210114090926.12109-1-lengchao@huawei.com>
Message-ID: <20210114090926.12109-2-lengchao@huawei.com>

A crash happens when inject completing request long time(nearly 30s).
Each name space has a request queue, when inject completing request long
time, multi request queues may have time out requests at the same time,
nvme_rdma_timeout will execute concurrently. Multi requests in different
request queues may be queued in the same rdma queue, multi
nvme_rdma_timeout may call nvme_rdma_stop_queue at the same time.
The first nvme_rdma_timeout will clear NVME_RDMA_Q_LIVE and continue
stopping the rdma queue(drain qp), but the others check NVME_RDMA_Q_LIVE
is already cleared, and then directly complete the requests, complete
request before the qp is fully drained may lead to a use-after-free
condition.

Add a multex lock to serialize nvme_rdma_stop_queue.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 drivers/nvme/host/rdma.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index df9f6f4549f1..7b10315e03de 100644
--- a/drivers/nvme/host/rdma.c
+++ b/drivers/nvme/host/rdma.c
@@ -97,6 +97,7 @@ struct nvme_rdma_queue {
 	struct completion	cm_done;
 	bool			pi_support;
 	int			cq_size;
+	struct mutex		queue_lock;
 };
 
 struct nvme_rdma_ctrl {
@@ -579,6 +580,7 @@ static int nvme_rdma_alloc_queue(struct nvme_rdma_ctrl *ctrl,
 	int ret;
 
 	queue = &ctrl->queues[idx];
+	mutex_init(&queue->queue_lock);
 	queue->ctrl = ctrl;
 	if (idx && ctrl->ctrl.max_integrity_segments)
 		queue->pi_support = true;
@@ -598,7 +600,8 @@ static int nvme_rdma_alloc_queue(struct nvme_rdma_ctrl *ctrl,
 	if (IS_ERR(queue->cm_id)) {
 		dev_info(ctrl->ctrl.device,
 			"failed to create CM ID: %ld\n", PTR_ERR(queue->cm_id));
-		return PTR_ERR(queue->cm_id);
+		ret = PTR_ERR(queue->cm_id);
+		goto out_destroy_mutex;
 	}
 
 	if (ctrl->ctrl.opts->mask & NVMF_OPT_HOST_TRADDR)
@@ -628,6 +631,8 @@ static int nvme_rdma_alloc_queue(struct nvme_rdma_ctrl *ctrl,
 out_destroy_cm_id:
 	rdma_destroy_id(queue->cm_id);
 	nvme_rdma_destroy_queue_ib(queue);
+out_destroy_mutex:
+	mutex_destroy(&queue->queue_lock);
 	return ret;
 }
 
@@ -639,9 +644,10 @@ static void __nvme_rdma_stop_queue(struct nvme_rdma_queue *queue)
 
 static void nvme_rdma_stop_queue(struct nvme_rdma_queue *queue)
 {
-	if (!test_and_clear_bit(NVME_RDMA_Q_LIVE, &queue->flags))
-		return;
-	__nvme_rdma_stop_queue(queue);
+	mutex_lock(&queue->queue_lock);
+	if (test_and_clear_bit(NVME_RDMA_Q_LIVE, &queue->flags))
+		__nvme_rdma_stop_queue(queue);
+	mutex_unlock(&queue->queue_lock);
 }
 
 static void nvme_rdma_free_queue(struct nvme_rdma_queue *queue)
@@ -651,6 +657,7 @@ static void nvme_rdma_free_queue(struct nvme_rdma_queue *queue)
 
 	nvme_rdma_destroy_queue_ib(queue);
 	rdma_destroy_id(queue->cm_id);
+	mutex_destroy(&queue->queue_lock);
 }
 
 static void nvme_rdma_free_io_queues(struct nvme_rdma_ctrl *ctrl)
-- 
2.16.4



From lengchao at huawei.com  Thu Jan 14 04:09:26 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 14 Jan 2021 17:09:26 +0800
Subject: [PATCH v2 2/2] nvme-tcp: avoid request double completion for
 concurrent nvme_tcp_timeout
In-Reply-To: <20210114090926.12109-1-lengchao@huawei.com>
References: <20210114090926.12109-1-lengchao@huawei.com>
Message-ID: <20210114090926.12109-3-lengchao@huawei.com>

Each name space has a request queue, if complete request long time,
multi request queues may have time out requests at the same time,
nvme_tcp_timeout will execute concurrently. Multi requests in different
request queues may be queued in the same tcp queue, multi
nvme_tcp_timeout may call nvme_tcp_stop_queue at the same time.
The first nvme_tcp_stop_queue will clear NVME_TCP_Q_LIVE and continue
stopping the tcp queue(cancel io_work), but the others check
NVME_TCP_Q_LIVE is already cleared, and then directly complete the
requests, complete request before the io work is completely canceled may
lead to a use-after-free condition.
Add a multex lock to serialize nvme_tcp_stop_queue.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 drivers/nvme/host/tcp.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 1ba659927442..725f80984d54 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -76,6 +76,7 @@ struct nvme_tcp_queue {
 	struct work_struct	io_work;
 	int			io_cpu;
 
+	struct mutex		queue_lock;
 	struct mutex		send_mutex;
 	struct llist_head	req_list;
 	struct list_head	send_list;
@@ -1209,6 +1210,7 @@ static void nvme_tcp_free_queue(struct nvme_ctrl *nctrl, int qid)
 
 	sock_release(queue->sock);
 	kfree(queue->pdu);
+	mutex_destroy(&queue->queue_lock);
 }
 
 static int nvme_tcp_init_connection(struct nvme_tcp_queue *queue)
@@ -1370,6 +1372,7 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl,
 	struct nvme_tcp_queue *queue = &ctrl->queues[qid];
 	int ret, rcv_pdu_size;
 
+	mutex_init(&queue->queue_lock);
 	queue->ctrl = ctrl;
 	init_llist_head(&queue->req_list);
 	INIT_LIST_HEAD(&queue->send_list);
@@ -1388,7 +1391,7 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl,
 	if (ret) {
 		dev_err(nctrl->device,
 			"failed to create socket: %d\n", ret);
-		return ret;
+		goto err_destroy_mutex;
 	}
 
 	/* Single syn retry */
@@ -1497,6 +1500,8 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl,
 err_sock:
 	sock_release(queue->sock);
 	queue->sock = NULL;
+err_destroy_mutex:
+	mutex_destroy(&queue->queue_lock);
 	return ret;
 }
 
@@ -1524,9 +1529,10 @@ static void nvme_tcp_stop_queue(struct nvme_ctrl *nctrl, int qid)
 	struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl);
 	struct nvme_tcp_queue *queue = &ctrl->queues[qid];
 
-	if (!test_and_clear_bit(NVME_TCP_Q_LIVE, &queue->flags))
-		return;
-	__nvme_tcp_stop_queue(queue);
+	mutex_lock(&queue->queue_lock);
+	if (test_and_clear_bit(NVME_TCP_Q_LIVE, &queue->flags))
+		__nvme_tcp_stop_queue(queue);
+	mutex_unlock(&queue->queue_lock);
 }
 
 static int nvme_tcp_start_queue(struct nvme_ctrl *nctrl, int idx)
-- 
2.16.4



From hare at suse.de  Thu Jan 14 06:12:53 2021
From: hare at suse.de (Hannes Reinecke)
Date: Thu, 14 Jan 2021 12:12:53 +0100
Subject: [PATCH 1/1] nvme: update enumerations for status codes
In-Reply-To: <20210104125947.160984-1-mgurtovoy@nvidia.com>
References: <20210104125947.160984-1-mgurtovoy@nvidia.com>
Message-ID: <a6251b7c-e2aa-7967-2e20-2983905818a8@suse.de>

On 1/4/21 1:59 PM, Max Gurtovoy wrote:
> All the updates are mentioned in the ratified NVMe 1.4 spec.
> 
> Signed-off-by: Max Gurtovoy <mgurtovoy at nvidia.com>
> ---
>   include/linux/nvme.h | 24 ++++++++++++++++++++----
>   1 file changed, 20 insertions(+), 4 deletions(-)
> 
> diff --git a/include/linux/nvme.h b/include/linux/nvme.h
> index d92535997687..1c9c34be8194 100644
> --- a/include/linux/nvme.h
> +++ b/include/linux/nvme.h
> @@ -1467,20 +1467,29 @@ enum {
>   	NVME_SC_SGL_INVALID_DATA	= 0xf,
>   	NVME_SC_SGL_INVALID_METADATA	= 0x10,
>   	NVME_SC_SGL_INVALID_TYPE	= 0x11,
> -
> +	NVME_SC_CMB_INVALID_USE		= 0x12,
> +	NVME_SC_PRP_INVALID_OFFSET	= 0x13,
> +	NVME_SC_ATOMIC_WU_EXCEEDED	= 0x14,
> +	NVME_SC_OP_DENIED		= 0x15,
>   	NVME_SC_SGL_INVALID_OFFSET	= 0x16,
> -	NVME_SC_SGL_INVALID_SUBTYPE	= 0x17,
> -
> +	NVME_SC_RESERVED		= 0x17,
> +	NVME_SC_HOST_ID_INCONSIST	= 0x18,
> +	NVME_SC_KA_TIMEOUT_EXPIRED	= 0x19,
> +	NVME_SC_KA_TIMEOUT_INVALID	= 0x1A,
> +	NVME_SC_ABORTED_PREEMPT_ABORT	= 0x1B,
>   	NVME_SC_SANITIZE_FAILED		= 0x1C,
>   	NVME_SC_SANITIZE_IN_PROGRESS	= 0x1D,
> -
> +	NVME_SC_SGL_INVALID_GRANULARITY	= 0x1E,
> +	NVME_SC_CMD_NOT_SUP_CMB_QUEUE	= 0x1F,
>   	NVME_SC_NS_WRITE_PROTECTED	= 0x20,
>   	NVME_SC_CMD_INTERRUPTED		= 0x21,
> +	NVME_SC_TRANSIENT_TR_ERR	= 0x22,
>   
>   	NVME_SC_LBA_RANGE		= 0x80,
>   	NVME_SC_CAP_EXCEEDED		= 0x81,
>   	NVME_SC_NS_NOT_READY		= 0x82,
>   	NVME_SC_RESERVATION_CONFLICT	= 0x83,
> +	NVME_SC_FORMAT_IN_PROGRESS	= 0x84,
>   
>   	/*
>   	 * Command Specific Status:
> @@ -1513,8 +1522,15 @@ enum {
>   	NVME_SC_NS_NOT_ATTACHED		= 0x11a,
>   	NVME_SC_THIN_PROV_NOT_SUPP	= 0x11b,
>   	NVME_SC_CTRL_LIST_INVALID	= 0x11c,
> +	NVME_SC_SELT_TEST_IN_PROGRESS	= 0x11d,
>   	NVME_SC_BP_WRITE_PROHIBITED	= 0x11e,
> +	NVME_SC_CTRL_ID_INVALID		= 0x11f,
> +	NVME_SC_SEC_CTRL_STATE_INVALID	= 0x120,
> +	NVME_SC_CTRL_RES_NUM_INVALID	= 0x121,
> +	NVME_SC_RES_ID_INVALID		= 0x122,
>   	NVME_SC_PMR_SAN_PROHIBITED	= 0x123,
> +	NVME_SC_ANA_GROUP_ID_INVALID	= 0x124,
> +	NVME_SC_ANA_ATTACH_FAILED	= 0x125,
>   
>   	/*
>   	 * I/O Command Set Specific - NVM commands:
> 
Reviewed-by: Hannes Reinecke <hare at suse.de>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare at suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 N?rnberg
HRB 36809 (AG N?rnberg), Gesch?ftsf?hrer: Felix Imend?rffer


From Elad.Grupi at dell.com  Thu Jan 14 06:49:23 2021
From: Elad.Grupi at dell.com (Grupi, Elad)
Date: Thu, 14 Jan 2021 11:49:23 +0000
Subject: kernel panic in nvmet_tcp when receiving malformed admin command
In-Reply-To: <2f2b2df4-ba06-a7ae-23cf-31eb17998c6e@grimberg.me>
References: <BL0PR1901MB2067C827A2D826C0FBFE985591320@BL0PR1901MB2067.namprd19.prod.outlook.com>
 <cee26269-c9c3-7ce7-8486-4ed16a632e44@grimberg.me>
 <BL0PR1901MB20671CF789D8C246AF911B4D91330@BL0PR1901MB2067.namprd19.prod.outlook.com>
 <DS7PR19MB4439372515F931BA5A1578ABEED30@DS7PR19MB4439.namprd19.prod.outlook.com>
 <dec5fc1d-62d6-1c1e-e2f8-4aa5aeb084af@grimberg.me>
 <2f2b2df4-ba06-a7ae-23cf-31eb17998c6e@grimberg.me>
Message-ID: <DM6PR19MB401188A9DCF3FCC762A3CCE4EFA80@DM6PR19MB4011.namprd19.prod.outlook.com>

Hi Sagi

This patch did not solve the below issue. We still see the same kernel panic.
We reproduce the issue by adding a validation to the resv1 field in connect command.

Few comments about your patch:

In nvmet_tcp_unmap_cmds, need to use queue->connect instead of cmd:
+               /* failed in connect */
+               nvmet_tcp_unmap_pdu_iovec(cmd);
+               nvmet_tcp_unmap_data(cmd);

Also in nvmet_tcp_uninit_data_in_cmds same issue:
                 /* failed in connect */
-               nvmet_tcp_finish_cmd(&queue->connect);
+               nvmet_req_uninit(&cmd->req);

Elad

-----Original Message-----
From: Linux-nvme <linux-nvme-bounces at lists.infradead.org> On Behalf Of Sagi Grimberg
Sent: Friday, 8 January 2021 22:24
To: Engel, Amit; Anner, Ran; linux-nvme at lists.infradead.org
Cc: Zinger, Eldad; Grupi, Elad
Subject: Re: kernel panic in nvmet_tcp when receiving malformed admin command


[EXTERNAL EMAIL] 


>> Hi Sagi, is the patch addressing the below issue is already out there?
> 
> No, thanks for reminding me, I'll have a look into this.

Amit, Ran,

Does this solve your issue?
This needs to split to patches but would be good to understand if this works.
--
diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c index dc1f0f647189..c41902f7ce39 100644
--- a/drivers/nvme/target/tcp.c
+++ b/drivers/nvme/target/tcp.c
@@ -204,7 +204,6 @@ nvmet_tcp_get_cmd(struct nvmet_tcp_queue *queue)
         cmd->rbytes_done = cmd->wbytes_done = 0;
         cmd->pdu_len = 0;
         cmd->pdu_recv = 0;
-       cmd->iov = NULL;
         cmd->flags = 0;
         return cmd;
  }
@@ -294,6 +293,7 @@ static void nvmet_tcp_unmap_pdu_iovec(struct nvmet_tcp_cmd *cmd)

         for (i = 0; i < cmd->nr_mapped; i++)
                 kunmap(sg_page(&sg[i]));
+       cmd->nr_mapped = 0;
  }

  static void nvmet_tcp_map_pdu_iovec(struct nvmet_tcp_cmd *cmd) @@ -341,6 +341,14 @@ static void nvmet_tcp_socket_error(struct nvmet_tcp_queue *queue, int status)
                 nvmet_tcp_fatal_error(queue);
  }

+static void nvmet_tcp_unmap_data(struct nvmet_tcp_cmd *cmd) {
+       kfree(cmd->iov);
+       cmd->iov = NULL;
+       sgl_free(cmd->req.sg);
+       cmd->req.sg = NULL;
+}
+
  static int nvmet_tcp_map_data(struct nvmet_tcp_cmd *cmd)
  {
         struct nvme_sgl_desc *sgl = &cmd->req.cmd->common.dptr.sgl; @@ -375,6 +383,7 @@ static int nvmet_tcp_map_data(struct nvmet_tcp_cmd *cmd)
         return 0;
  err:
         sgl_free(cmd->req.sg);
+       cmd->req.sg = NULL;
         return NVME_SC_INTERNAL;
  }

@@ -571,17 +580,13 @@ static int nvmet_try_send_data(struct nvmet_tcp_cmd *cmd, bool last_in_batch)
         } else {
                 if (queue->nvme_sq.sqhd_disabled) {
                         cmd->queue->snd_cmd = NULL;
+                       nvmet_tcp_unmap_data(cmd);
                         nvmet_tcp_put_cmd(cmd);
                 } else {
                         nvmet_setup_response_pdu(cmd);
                 }
         }

-       if (queue->nvme_sq.sqhd_disabled) {
-               kfree(cmd->iov);
-               sgl_free(cmd->req.sg);
-       }
-
         return 1;

  }
@@ -609,9 +614,8 @@ static int nvmet_try_send_response(struct nvmet_tcp_cmd *cmd,
         if (left)
                 return -EAGAIN;

-       kfree(cmd->iov);
-       sgl_free(cmd->req.sg);
         cmd->queue->snd_cmd = NULL;
+       nvmet_tcp_unmap_data(cmd);
         nvmet_tcp_put_cmd(cmd);
         return 1;
  }
@@ -665,6 +669,7 @@ static int nvmet_try_send_ddgst(struct nvmet_tcp_cmd *cmd, bool last_in_batch)

         if (queue->nvme_sq.sqhd_disabled) {
                 cmd->queue->snd_cmd = NULL;
+               nvmet_tcp_unmap_data(cmd);
                 nvmet_tcp_put_cmd(cmd);
         } else {
                 nvmet_setup_response_pdu(cmd); @@ -1082,15 +1087,16 @@ static int nvmet_tcp_try_recv_data(struct nvmet_tcp_queue *queue)

         nvmet_tcp_unmap_pdu_iovec(cmd);

-       if (!(cmd->flags & NVMET_TCP_F_INIT_FAILED) &&
-           cmd->rbytes_done == cmd->req.transfer_len) {
-               if (queue->data_digest) {
-                       nvmet_tcp_prep_recv_ddgst(cmd);
-                       return 0;
-               }
-               cmd->req.execute(&cmd->req);
+       if (queue->data_digest) {
+               nvmet_tcp_prep_recv_ddgst(cmd);
+               return 0;
         }

+       if (unlikely(cmd->flags & NVMET_TCP_F_INIT_FAILED))
+               nvmet_tcp_finish_cmd(cmd);
+       else if (cmd->rbytes_done == cmd->req.transfer_len)
+               cmd->req.execute(&cmd->req);
+
         nvmet_prepare_receive_pdu(queue);
         return 0;
  }
@@ -1120,14 +1126,16 @@ static int nvmet_tcp_try_recv_ddgst(struct nvmet_tcp_queue *queue)
                         queue->idx, cmd->req.cmd->common.command_id,
                         queue->pdu.cmd.hdr.type, le32_to_cpu(cmd->recv_ddgst),
                         le32_to_cpu(cmd->exp_ddgst));
+               nvmet_req_uninit(&cmd->req);
                 nvmet_tcp_finish_cmd(cmd);
                 nvmet_tcp_fatal_error(queue);
                 ret = -EPROTO;
                 goto out;
         }

-       if (!(cmd->flags & NVMET_TCP_F_INIT_FAILED) &&
-           cmd->rbytes_done == cmd->req.transfer_len)
+       if (unlikely(cmd->flags & NVMET_TCP_F_INIT_FAILED))
+               nvmet_tcp_finish_cmd(cmd);
+       else if (cmd->rbytes_done == cmd->req.transfer_len)
                 cmd->req.execute(&cmd->req);
         ret = 0;
  out:
@@ -1139,7 +1147,8 @@ static int nvmet_tcp_try_recv_one(struct nvmet_tcp_queue *queue)
  {
         int result = 0;

-       if (unlikely(queue->rcv_state == NVMET_TCP_RECV_ERR))
+       if (unlikely(queue->rcv_state == NVMET_TCP_RECV_ERR ||
+                    queue->state == NVMET_TCP_Q_DISCONNECTING))
                 return 0;

         if (queue->rcv_state == NVMET_TCP_RECV_PDU) { @@ -1333,10 +1342,26 @@ static void nvmet_tcp_restore_socket_callbacks(struct nvmet_tcp_queue *queue)

  static void nvmet_tcp_finish_cmd(struct nvmet_tcp_cmd *cmd)
  {
-       nvmet_req_uninit(&cmd->req);
         nvmet_tcp_unmap_pdu_iovec(cmd);
-       kfree(cmd->iov);
-       sgl_free(cmd->req.sg);
+       nvmet_tcp_unmap_data(cmd);
+       nvmet_tcp_put_cmd(cmd);
+}
+
+static void nvmet_tcp_unmap_cmds(struct nvmet_tcp_queue *queue) {
+       struct nvmet_tcp_cmd *cmd = queue->cmds;
+       int i;
+
+       for (i = 0; i < queue->nr_cmds; i++, cmd++) {
+               nvmet_tcp_unmap_pdu_iovec(cmd);
+               nvmet_tcp_unmap_data(cmd);
+       }
+
+       if (!queue->nr_cmds) {
+               /* failed in connect */
+               nvmet_tcp_unmap_pdu_iovec(cmd);
+               nvmet_tcp_unmap_data(cmd);
+       }
  }

  static void nvmet_tcp_uninit_data_in_cmds(struct nvmet_tcp_queue *queue) @@ -1346,12 +1371,12 @@ static void nvmet_tcp_uninit_data_in_cmds(struct
nvmet_tcp_queue *queue)

         for (i = 0; i < queue->nr_cmds; i++, cmd++) {
                 if (nvmet_tcp_need_data_in(cmd))
-                       nvmet_tcp_finish_cmd(cmd);
+                       nvmet_req_uninit(&cmd->req);
         }

         if (!queue->nr_cmds && nvmet_tcp_need_data_in(&queue->connect)) {
                 /* failed in connect */
-               nvmet_tcp_finish_cmd(&queue->connect);
+               nvmet_req_uninit(&cmd->req);
         }
  }

@@ -1370,6 +1395,7 @@ static void nvmet_tcp_release_queue_work(struct
work_struct *w)
         nvmet_tcp_uninit_data_in_cmds(queue);
         nvmet_sq_destroy(&queue->nvme_sq);
         cancel_work_sync(&queue->io_work);
+       nvmet_tcp_unmap_cmds(queue);
         sock_release(queue->sock);
         nvmet_tcp_free_cmds(queue);
         if (queue->hdr_digest || queue->data_digest)
--

_______________________________________________
Linux-nvme mailing list
Linux-nvme at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-nvme

From Elad.Grupi at dell.com  Thu Jan 14 06:51:05 2021
From: Elad.Grupi at dell.com (Grupi, Elad)
Date: Thu, 14 Jan 2021 11:51:05 +0000
Subject: [PATCH] nvme-tcp: fix a segmentation fault during io parsing error
In-Reply-To: <ad9f038b-9920-21da-755c-85f4e2228a22@grimberg.me>
References: <20210113115152.69692-1-elad.grupi@dell.com>
 <ad9f038b-9920-21da-755c-85f4e2228a22@grimberg.me>
Message-ID: <DM6PR19MB401194016A086DDF8A82C554EFA80@DM6PR19MB4011.namprd19.prod.outlook.com>

Thank you Sagi,

I will submit a new patch with a comment as requested.
The patch you sent did not solve that issue, I submitted some comments on the relevant thread.

Elad

-----Original Message-----
From: Sagi Grimberg <sagi at grimberg.me> 
Sent: Thursday, 14 January 2021 0:47
To: Grupi, Elad; linux-nvme at lists.infradead.org
Subject: Re: [PATCH] nvme-tcp: fix a segmentation fault during io parsing error


[EXTERNAL EMAIL] 

Hey Elad,

> From: Elad Grupi <elad.grupi at dell.com>
> 
>      In case there is an io that contains inline data and it goes to
>      parsing error flow, command response will free command and iov
>      before clearing the data on the socket buffer.
>      This will delay the command response until receive flow is completed.
> 
> Signed-off-by: Elad Grupi <elad.grupi at dell.com>
> ---
>   drivers/nvme/target/tcp.c | 7 ++++++-
>   1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c 
> index d535080b781f..dea94da4c9ba 100644
> --- a/drivers/nvme/target/tcp.c
> +++ b/drivers/nvme/target/tcp.c
> @@ -146,6 +146,7 @@ static struct workqueue_struct *nvmet_tcp_wq;
>   static struct nvmet_fabrics_ops nvmet_tcp_ops;
>   static void nvmet_tcp_free_cmd(struct nvmet_tcp_cmd *c);
>   static void nvmet_tcp_finish_cmd(struct nvmet_tcp_cmd *cmd);
> +static void nvmet_tcp_queue_response(struct nvmet_req *req);
>   
>   static inline u16 nvmet_tcp_cmd_tag(struct nvmet_tcp_queue *queue,
>   		struct nvmet_tcp_cmd *cmd)
> @@ -476,7 +477,11 @@ static struct nvmet_tcp_cmd *nvmet_tcp_fetch_cmd(struct nvmet_tcp_queue *queue)
>   		nvmet_setup_c2h_data_pdu(queue->snd_cmd);
>   	else if (nvmet_tcp_need_data_in(queue->snd_cmd))
>   		nvmet_setup_r2t_pdu(queue->snd_cmd);
> -	else
> +	else if (nvmet_tcp_has_data_in(queue->snd_cmd) &&
> +			nvmet_tcp_has_inline_data(queue->snd_cmd)) {

This deserves a comment I think.

Did you get a chance to look into what I sent you guys?

> +		nvmet_tcp_queue_response(&queue->snd_cmd->req);
> +		queue->snd_cmd = NULL;
> +	} else
>   		nvmet_setup_response_pdu(queue->snd_cmd);
>   
>   	return queue->snd_cmd;
> 

From elad.grupi at dell.com  Thu Jan 14 08:04:48 2021
From: elad.grupi at dell.com (elad.grupi at dell.com)
Date: Thu, 14 Jan 2021 15:04:48 +0200
Subject: [PATCH] nvme-tcp: fix a segmentation fault during io parsing error
Message-ID: <20210114130448.91349-1-elad.grupi@dell.com>

From: Elad Grupi <elad.grupi at dell.com>

    In case there is an io that contains inline data and it goes to
    parsing error flow, command response will free command and iov
    before clearing the data on the socket buffer.
    This will delay the command response until receive flow is completed.

Signed-off-by: Elad Grupi <elad.grupi at dell.com>
---
 drivers/nvme/target/tcp.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
index d535080b781f..f181744b0214 100644
--- a/drivers/nvme/target/tcp.c
+++ b/drivers/nvme/target/tcp.c
@@ -146,6 +146,7 @@ static struct workqueue_struct *nvmet_tcp_wq;
 static struct nvmet_fabrics_ops nvmet_tcp_ops;
 static void nvmet_tcp_free_cmd(struct nvmet_tcp_cmd *c);
 static void nvmet_tcp_finish_cmd(struct nvmet_tcp_cmd *cmd);
+static void nvmet_tcp_queue_response(struct nvmet_req *req);
 
 static inline u16 nvmet_tcp_cmd_tag(struct nvmet_tcp_queue *queue,
 		struct nvmet_tcp_cmd *cmd)
@@ -476,7 +477,15 @@ static struct nvmet_tcp_cmd *nvmet_tcp_fetch_cmd(struct nvmet_tcp_queue *queue)
 		nvmet_setup_c2h_data_pdu(queue->snd_cmd);
 	else if (nvmet_tcp_need_data_in(queue->snd_cmd))
 		nvmet_setup_r2t_pdu(queue->snd_cmd);
-	else
+	else if (nvmet_tcp_has_data_in(queue->snd_cmd) &&
+			nvmet_tcp_has_inline_data(queue->snd_cmd)) {
+		/*
+		 * wait for inline data before processing the response
+		 * so the iov will not be freed
+		 */
+		nvmet_tcp_queue_response(&queue->snd_cmd->req);
+		queue->snd_cmd = NULL;
+	} else
 		nvmet_setup_response_pdu(queue->snd_cmd);
 
 	return queue->snd_cmd;
-- 
2.16.5



From its at irrelevant.dk  Thu Jan 14 08:24:41 2021
From: its at irrelevant.dk (Klaus Jensen)
Date: Thu, 14 Jan 2021 14:24:41 +0100
Subject: [PATCH] nvme: allow use of cmb on v1.4 controllers
Message-ID: <20210114132441.193782-1-its@irrelevant.dk>

From: Klaus Jensen <k.jensen at samsung.com>

Since NVMe v1.4 the Controller Memory Buffer must be explicitly enabled
by the host.

Signed-off-by: Klaus Jensen <k.jensen at samsung.com>
---
 drivers/nvme/host/pci.c | 25 ++++++++++++++++++++++++-
 include/linux/nvme.h    |  6 ++++++
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 50d9a20568a2..9c2bbb242994 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -1787,7 +1787,8 @@ static u32 nvme_cmb_size(struct nvme_dev *dev)
 
 static void nvme_map_cmb(struct nvme_dev *dev)
 {
-	u64 size, offset;
+	u32 vs;
+	u64 size, offset, cmbmsc;
 	resource_size_t bar_size;
 	struct pci_dev *pdev = to_pci_dev(dev->dev);
 	int bar;
@@ -1795,6 +1796,15 @@ static void nvme_map_cmb(struct nvme_dev *dev)
 	if (dev->cmb_size)
 		return;
 
+	vs = readl(dev->bar + NVME_REG_VS);
+
+	if (vs >= NVME_VS(1, 4, 0)) {
+		if (!NVME_CAP_CMBS(dev->ctrl.cap))
+			return;
+
+		writel(NVME_CMBMSC_CRE, dev->bar + NVME_REG_CMBMSC);
+	}
+
 	dev->cmbsz = readl(dev->bar + NVME_REG_CMBSZ);
 	if (!dev->cmbsz)
 		return;
@@ -1805,6 +1815,19 @@ static void nvme_map_cmb(struct nvme_dev *dev)
 	bar = NVME_CMB_BIR(dev->cmbloc);
 	bar_size = pci_resource_len(pdev, bar);
 
+	if (vs >= NVME_VS(1, 4, 0)) {
+		cmbmsc = pci_resource_start(pdev, bar);
+		cmbmsc |= (NVME_CMBMSC_CRE | NVME_CMBMSC_CMSE);
+
+		/*
+		 * Writing the low bits may cause the controller to check the
+		 * validity of the 52 bit controller base address in the CMBMSC
+		 * register, so write the high bits first.
+		 */
+		writel(cmbmsc >> 32, dev->bar + NVME_REG_CMBMSC + 4);
+		writel(cmbmsc, dev->bar + NVME_REG_CMBMSC);
+	}
+
 	if (offset > bar_size)
 		return;
 
diff --git a/include/linux/nvme.h b/include/linux/nvme.h
index d92535997687..bfed36e342cc 100644
--- a/include/linux/nvme.h
+++ b/include/linux/nvme.h
@@ -116,6 +116,9 @@ enum {
 	NVME_REG_BPMBL	= 0x0048,	/* Boot Partition Memory Buffer
 					 * Location
 					 */
+	NVME_REG_CMBMSC = 0x0050,	/* Controller Memory Buffer Memory
+					 * Space Control
+					 */
 	NVME_REG_PMRCAP	= 0x0e00,	/* Persistent Memory Capabilities */
 	NVME_REG_PMRCTL	= 0x0e04,	/* Persistent Memory Region Control */
 	NVME_REG_PMRSTS	= 0x0e08,	/* Persistent Memory Region Status */
@@ -135,6 +138,7 @@ enum {
 #define NVME_CAP_CSS(cap)	(((cap) >> 37) & 0xff)
 #define NVME_CAP_MPSMIN(cap)	(((cap) >> 48) & 0xf)
 #define NVME_CAP_MPSMAX(cap)	(((cap) >> 52) & 0xf)
+#define NVME_CAP_CMBS(cap)	(((cap) >> 57) & 0x1)
 
 #define NVME_CMB_BIR(cmbloc)	((cmbloc) & 0x7)
 #define NVME_CMB_OFST(cmbloc)	(((cmbloc) >> 12) & 0xfffff)
@@ -192,6 +196,8 @@ enum {
 	NVME_CSTS_SHST_OCCUR	= 1 << 2,
 	NVME_CSTS_SHST_CMPLT	= 2 << 2,
 	NVME_CSTS_SHST_MASK	= 3 << 2,
+	NVME_CMBMSC_CRE		= 1 << 0,
+	NVME_CMBMSC_CMSE	= 1 << 1,
 };
 
 struct nvme_id_power_state {
-- 
2.30.0



From minwoo.im.dev at gmail.com  Thu Jan 14 08:31:07 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Thu, 14 Jan 2021 22:31:07 +0900
Subject: [PATCH V3 0/3] nvme: fixes for command retry
Message-ID: <20210114133110.20779-1-minwoo.im.dev@gmail.com>

Hello,

Here's V3 patch series for Advanced Command Retery Enable (ACRE).  This
series enables command retry feature based on a flag introduced to nvme
controller instance in this series.

This patchset placed ACRE flag check first than REQ_FAILFAST_* cmd_flags
checking.  It makes Set Feature for Host Bevior in reset_work more
meaningful.

Please review.

Thanks!

Since V2:
  - Update commit description more informative. (Sagi)
  - Split [2/2] patch into two patches. (Sagi)
  - Fix condition to return COMPLETE in [2/2]. (Chao and Keith)

Since V1:
  - The first patch has been applied (Christoph).  Removed from this
    series.
  - Update the last patch to take acre flag from the controller
    instance instead of module parameter by updating
    nvme_decide_disposition().  (Chao)

Minwoo Im (3):
  nvme: check all retry delay times in Identify Controller
  nvme: introduce acre flag in nvme_ctrl
  nvme: retry commands based on ACRE flag

 drivers/nvme/host/core.c | 18 +++++++++++++++---
 drivers/nvme/host/nvme.h |  1 +
 2 files changed, 16 insertions(+), 3 deletions(-)

-- 
2.17.1



From minwoo.im.dev at gmail.com  Thu Jan 14 08:31:08 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Thu, 14 Jan 2021 22:31:08 +0900
Subject: [PATCH V3 1/3] nvme: check all retry delay times in Identify
 Controller
In-Reply-To: <20210114133110.20779-1-minwoo.im.dev@gmail.com>
References: <20210114133110.20779-1-minwoo.im.dev@gmail.com>
Message-ID: <20210114133110.20779-2-minwoo.im.dev@gmail.com>

If none of Command Retry Delay Time(CRDT)s are set, then we can simply
skip to configure Advanced Command Retry Enable(ACRE).

CRDT selection will be made in Completion Queue Entry that controller
has responsibility to decide.

This patch checks all CRDT[0, 1, and 2] in Identify Controller data
structrure instead of checking the first one: CRDT[0] for cases that:

	- CRDT[0] == 0, but CRDT[1 or 2] != 0

Signed-off-by: Minwoo Im <minwoo.im.dev at gmail.com>
---
 drivers/nvme/host/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index fff49e544fdf..a8cee380b3c0 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -2499,7 +2499,7 @@ static int nvme_configure_acre(struct nvme_ctrl *ctrl)
 	int ret;
 
 	/* Don't bother enabling the feature if retry delay is not reported */
-	if (!ctrl->crdt[0])
+	if (!ctrl->crdt[0] && !ctrl->crdt[1] && !ctrl->crdt[2])
 		return 0;
 
 	host = kzalloc(sizeof(*host), GFP_KERNEL);
-- 
2.17.1



From minwoo.im.dev at gmail.com  Thu Jan 14 08:31:09 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Thu, 14 Jan 2021 22:31:09 +0900
Subject: [PATCH V3 2/3] nvme: introduce acre flag in nvme_ctrl
In-Reply-To: <20210114133110.20779-1-minwoo.im.dev@gmail.com>
References: <20210114133110.20779-1-minwoo.im.dev@gmail.com>
Message-ID: <20210114133110.20779-3-minwoo.im.dev@gmail.com>

Advanced Command Retry Enable (ACRE) flag is added in nvme_ctrl
instance to indicate that Set Features for Host Behavior Support with
ACRE enabled is whether successfully done or not during reset_work.

This flag will be used to decide to retry commands that fail or not in
the followed patch.

Signed-off-by: Minwoo Im <minwoo.im.dev at gmail.com>
---
 drivers/nvme/host/core.c | 6 ++++++
 drivers/nvme/host/nvme.h | 1 +
 2 files changed, 7 insertions(+)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index a8cee380b3c0..a286e3422c61 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -2498,6 +2498,8 @@ static int nvme_configure_acre(struct nvme_ctrl *ctrl)
 	struct nvme_feat_host_behavior *host;
 	int ret;
 
+	ctrl->acre = false;
+
 	/* Don't bother enabling the feature if retry delay is not reported */
 	if (!ctrl->crdt[0] && !ctrl->crdt[1] && !ctrl->crdt[2])
 		return 0;
@@ -2509,6 +2511,10 @@ static int nvme_configure_acre(struct nvme_ctrl *ctrl)
 	host->acre = NVME_ENABLE_ACRE;
 	ret = nvme_set_features(ctrl, NVME_FEAT_HOST_BEHAVIOR, 0,
 				host, sizeof(*host), NULL);
+
+	if (!ret)
+		ctrl->acre = true;
+
 	kfree(host);
 	return ret;
 }
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 88a6b97247f5..db8b45e8ffde 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -270,6 +270,7 @@ struct nvme_ctrl {
 #ifdef CONFIG_BLK_DEV_ZONED
 	u32 max_zone_append;
 #endif
+	bool acre;
 	u16 crdt[3];
 	u16 oncs;
 	u16 oacs;
-- 
2.17.1



From minwoo.im.dev at gmail.com  Thu Jan 14 08:31:10 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Thu, 14 Jan 2021 22:31:10 +0900
Subject: [PATCH V3 3/3] nvme: retry commands based on ACRE flag
In-Reply-To: <20210114133110.20779-1-minwoo.im.dev@gmail.com>
References: <20210114133110.20779-1-minwoo.im.dev@gmail.com>
Message-ID: <20210114133110.20779-4-minwoo.im.dev@gmail.com>

Allow nvme_decide_disposition() to retry commands with error by checking
Advanced Command Retry Enable (ACRE) flag of controller first than
REQ_FAILFAST_* cmd_flags.  But, we just can't allow all command failures
to be retried due to reasons like connecting may take too long due to
the retries.  This patch only allows non-host path error commands to be
retried.

Cc: Chao Leng <lengchao at huawei.com>
Cc: Sagi Grimberg <sagi at grimberg.me>
Cc: Keith Busch <kbusch at kernel.org>
Signed-off-by: Minwoo Im <minwoo.im.dev at gmail.com>
---
 drivers/nvme/host/core.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index a286e3422c61..e4f7c49c2f39 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -303,8 +303,7 @@ static inline enum nvme_disposition nvme_decide_disposition(struct request *req)
 	if (likely(nvme_req(req)->status == 0))
 		return COMPLETE;
 
-	if (blk_noretry_request(req) ||
-	    (nvme_req(req)->status & NVME_SC_DNR) ||
+	if ((nvme_req(req)->status & NVME_SC_DNR) ||
 	    nvme_req(req)->retries >= nvme_max_retries)
 		return COMPLETE;
 
@@ -317,6 +316,13 @@ static inline enum nvme_disposition nvme_decide_disposition(struct request *req)
 			return COMPLETE;
 	}
 
+	if (nvme_req(req)->ctrl->acre &&
+	    !nvme_is_path_error(nvme_req(req)->status) &&
+	    !blk_queue_dying(req->q))
+		return RETRY;
+	else if (blk_noretry_request(req))
+		return COMPLETE;
+
 	return RETRY;
 }
 
-- 
2.17.1



From borisp at mellanox.com  Thu Jan 14 10:10:26 2021
From: borisp at mellanox.com (Boris Pismenny)
Date: Thu, 14 Jan 2021 17:10:26 +0200
Subject: [PATCH v2 net-next 14/21] net/mlx5e: KLM UMR helper macros
In-Reply-To: <20210114151033.13020-1-borisp@mellanox.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
Message-ID: <20210114151033.13020-15-borisp@mellanox.com>

From: Ben Ben-Ishay <benishay at nvidia.com>

Add helper macros for posting KLM UMR WQE.

Signed-off-by: Boris Pismenny <borisp at mellanox.com>
Signed-off-by: Ben Ben-Ishay <benishay at nvidia.com>
Signed-off-by: Or Gerlitz <ogerlitz at mellanox.com>
Signed-off-by: Yoray Zack <yorayz at mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/en.h | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
index ff100c290b59..26259d68b98a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@ -152,6 +152,24 @@ struct page_pool;
 #define MLX5E_UMR_WQEBBS \
 	(DIV_ROUND_UP(MLX5E_UMR_WQE_INLINE_SZ, MLX5_SEND_WQE_BB))
 
+#define KLM_ALIGNMENT 4
+#define MLX5E_KLM_UMR_WQE_SZ(sgl_len)\
+	(sizeof(struct mlx5e_umr_wqe) +\
+	(sizeof(struct mlx5_klm) * (sgl_len)))
+
+#define MLX5E_KLM_UMR_WQEBBS(sgl_len)\
+	(DIV_ROUND_UP(MLX5E_KLM_UMR_WQE_SZ(sgl_len), MLX5_SEND_WQE_BB))
+
+#define MLX5E_KLM_UMR_DS_CNT(sgl_len)\
+	DIV_ROUND_UP(MLX5E_KLM_UMR_WQE_SZ(sgl_len), MLX5_SEND_WQE_DS)
+
+#define MLX5E_MAX_KLM_ENTRIES_PER_WQE(wqe_size)\
+	(((wqe_size) - sizeof(struct mlx5e_umr_wqe)) / sizeof(struct mlx5_klm))
+
+#define MLX5E_KLM_ENTRIES_PER_WQE(wqe_size)\
+	(MLX5E_MAX_KLM_ENTRIES_PER_WQE(wqe_size) -\
+			(MLX5E_MAX_KLM_ENTRIES_PER_WQE(wqe_size) % KLM_ALIGNMENT))
+
 #define MLX5E_MSG_LEVEL			NETIF_MSG_LINK
 
 #define mlx5e_dbg(mlevel, priv, format, ...)                    \
-- 
2.24.1



From borisp at mellanox.com  Thu Jan 14 10:10:13 2021
From: borisp at mellanox.com (Boris Pismenny)
Date: Thu, 14 Jan 2021 17:10:13 +0200
Subject: [PATCH v2 net-next 01/21] iov_iter: Introduce new procedures for copy
 to iter/pages
In-Reply-To: <20210114151033.13020-1-borisp@mellanox.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
Message-ID: <20210114151033.13020-2-borisp@mellanox.com>

When using direct data placement the NIC writes some of the payload
directly to the destination buffer, and constructs the SKB such that it
points to this data. As a result, the skb_copy datagram_iter call will
attempt to copy data when it is not necessary.

Introduce new procedures for copy to iter/pages in case that the
source of the copy operation might be identical to the destination,
in such cases the copy is skipped only for bio_vec, later commits
uses those functions to introduce new skb copy(+hash) functions.

Signed-off-by: Boris Pismenny <borisp at mellanox.com>
Signed-off-by: Ben Ben-Ishay <benishay at mellanox.com>
Signed-off-by: Or Gerlitz <ogerlitz at mellanox.com>
Signed-off-by: Yoray Zack <yorayz at mellanox.com>
---
 include/linux/uio.h | 12 ++++++++++++
 lib/iov_iter.c      | 45 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 57 insertions(+)

diff --git a/include/linux/uio.h b/include/linux/uio.h
index 72d88566694e..3c42125a7f24 100644
--- a/include/linux/uio.h
+++ b/include/linux/uio.h
@@ -123,6 +123,7 @@ size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes,
 			 struct iov_iter *i);
 
 size_t _copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i);
+size_t _ddp_copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i);
 size_t _copy_from_iter(void *addr, size_t bytes, struct iov_iter *i);
 bool _copy_from_iter_full(void *addr, size_t bytes, struct iov_iter *i);
 size_t _copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i);
@@ -137,6 +138,15 @@ size_t copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i)
 		return _copy_to_iter(addr, bytes, i);
 }
 
+static __always_inline __must_check
+size_t ddp_copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i)
+{
+	if (unlikely(!check_copy_size(addr, bytes, true)))
+		return 0;
+	else
+		return _ddp_copy_to_iter(addr, bytes, i);
+}
+
 static __always_inline __must_check
 size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i)
 {
@@ -265,6 +275,8 @@ size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, struct io
 bool csum_and_copy_from_iter_full(void *addr, size_t bytes, __wsum *csum, struct iov_iter *i);
 size_t hash_and_copy_to_iter(const void *addr, size_t bytes, void *hashp,
 		struct iov_iter *i);
+size_t ddp_hash_and_copy_to_iter(const void *addr, size_t bytes, void *hashp,
+		struct iov_iter *i);
 
 struct iovec *iovec_from_user(const struct iovec __user *uvector,
 		unsigned long nr_segs, unsigned long fast_segs,
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
index 1635111c5bd2..92c07cf4a3c9 100644
--- a/lib/iov_iter.c
+++ b/lib/iov_iter.c
@@ -473,6 +473,16 @@ static void memcpy_from_page(char *to, struct page *page, size_t offset, size_t
 	kunmap_atomic(from);
 }
 
+static void ddp_memcpy_to_page(struct page *page, size_t offset, const char *from, size_t len)
+{
+	char *to = kmap_atomic(page);
+
+	if (to + offset != from)
+		memcpy(to + offset, from, len);
+
+	kunmap_atomic(to);
+}
+
 static void memcpy_to_page(struct page *page, size_t offset, const char *from, size_t len)
 {
 	char *to = kmap_atomic(page);
@@ -625,6 +635,22 @@ static size_t csum_and_copy_to_pipe_iter(const void *addr, size_t bytes,
 	return bytes;
 }
 
+size_t _ddp_copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i)
+{
+	const char *from = addr;
+	if (unlikely(iov_iter_is_pipe(i)))
+		return copy_pipe_to_iter(addr, bytes, i);
+	if (iter_is_iovec(i))
+		might_fault();
+	iterate_and_advance(i, bytes, v, NULL,
+		ddp_memcpy_to_page(v.bv_page, v.bv_offset,
+				   (from += v.bv_len) - v.bv_len, v.bv_len),
+		NULL)
+
+	return bytes;
+}
+EXPORT_SYMBOL(_ddp_copy_to_iter);
+
 size_t _copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i)
 {
 	const char *from = addr;
@@ -1566,6 +1592,25 @@ size_t csum_and_copy_to_iter(const void *addr, size_t bytes, void *csump,
 }
 EXPORT_SYMBOL(csum_and_copy_to_iter);
 
+size_t ddp_hash_and_copy_to_iter(const void *addr, size_t bytes, void *hashp,
+		struct iov_iter *i)
+{
+#ifdef CONFIG_CRYPTO_HASH
+	struct ahash_request *hash = hashp;
+	struct scatterlist sg;
+	size_t copied;
+
+	copied = ddp_copy_to_iter(addr, bytes, i);
+	sg_init_one(&sg, addr, copied);
+	ahash_request_set_crypt(hash, &sg, NULL, copied);
+	crypto_ahash_update(hash);
+	return copied;
+#else
+	return 0;
+#endif
+}
+EXPORT_SYMBOL(ddp_hash_and_copy_to_iter);
+
 size_t hash_and_copy_to_iter(const void *addr, size_t bytes, void *hashp,
 		struct iov_iter *i)
 {
-- 
2.24.1



From borisp at mellanox.com  Thu Jan 14 10:10:16 2021
From: borisp at mellanox.com (Boris Pismenny)
Date: Thu, 14 Jan 2021 17:10:16 +0200
Subject: [PATCH v2 net-next 04/21] net: SKB copy(+hash) iterators for DDP
 offloads
In-Reply-To: <20210114151033.13020-1-borisp@mellanox.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
Message-ID: <20210114151033.13020-5-borisp@mellanox.com>

From: Ben Ben-ishay <benishay at nvidia.com>

This commit introduces new functions to support direct data placement
operation, when using direct data placement the copy of the data from
the SKB to the destination buffer might be unnecessary and thus the
copy should be skipped, those functions take care of it in cases that
the destination buffer is represented by bio_vec.

Signed-off-by: Boris Pismenny <borisp at mellanox.com>
Signed-off-by: Ben Ben-Ishay <benishay at nvidia.com>
Signed-off-by: Or Gerlitz <ogerlitz at mellanox.com>
Signed-off-by: Yoray Zack <yorayz at mellanox.com>
---
 include/linux/skbuff.h |  5 +++++
 net/core/datagram.c    | 44 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 49 insertions(+)

diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index a841bc974452..96847aabba5b 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -3536,6 +3536,8 @@ __poll_t datagram_poll(struct file *file, struct socket *sock,
 			   struct poll_table_struct *wait);
 int skb_copy_datagram_iter(const struct sk_buff *from, int offset,
 			   struct iov_iter *to, int size);
+int skb_ddp_copy_datagram_iter(const struct sk_buff *from, int offset,
+			       struct iov_iter *to, int size);
 static inline int skb_copy_datagram_msg(const struct sk_buff *from, int offset,
 					struct msghdr *msg, int size)
 {
@@ -3546,6 +3548,9 @@ int skb_copy_and_csum_datagram_msg(struct sk_buff *skb, int hlen,
 int skb_copy_and_hash_datagram_iter(const struct sk_buff *skb, int offset,
 			   struct iov_iter *to, int len,
 			   struct ahash_request *hash);
+int skb_ddp_copy_and_hash_datagram_iter(const struct sk_buff *skb, int offset,
+					struct iov_iter *to, int len,
+					struct ahash_request *hash);
 int skb_copy_datagram_from_iter(struct sk_buff *skb, int offset,
 				 struct iov_iter *from, int len);
 int zerocopy_sg_from_iter(struct sk_buff *skb, struct iov_iter *frm);
diff --git a/net/core/datagram.c b/net/core/datagram.c
index 81809fa735a7..bbc476cadc71 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -495,6 +495,25 @@ static int __skb_datagram_iter(const struct sk_buff *skb, int offset,
 	return 0;
 }
 
+/**
+ *	skb_ddp_copy_and_hash_datagram_iter - Copies datagrams from skb frags to
+ *	an iterator and update a hash. If the iterator and skb frag point to the
+ *	same page and offset, then the copy is skipped.
+ *	@skb: buffer to copy
+ *	@offset: offset in the buffer to start copying from
+ *	@to: iovec iterator to copy to
+ *	@len: amount of data to copy from buffer to iovec
+ *      @hash: hash request to update
+ */
+int skb_ddp_copy_and_hash_datagram_iter(const struct sk_buff *skb, int offset,
+					struct iov_iter *to, int len,
+					struct ahash_request *hash)
+{
+	return __skb_datagram_iter(skb, offset, to, len, true,
+			ddp_hash_and_copy_to_iter, hash);
+}
+EXPORT_SYMBOL(skb_ddp_copy_and_hash_datagram_iter);
+
 /**
  *	skb_copy_and_hash_datagram_iter - Copy datagram to an iovec iterator
  *          and update a hash.
@@ -513,6 +532,31 @@ int skb_copy_and_hash_datagram_iter(const struct sk_buff *skb, int offset,
 }
 EXPORT_SYMBOL(skb_copy_and_hash_datagram_iter);
 
+static size_t simple_ddp_copy_to_iter(const void *addr, size_t bytes,
+				      void *data __always_unused,
+				      struct iov_iter *i)
+{
+	return ddp_copy_to_iter(addr, bytes, i);
+}
+
+/**
+ *	skb_ddp_copy_datagram_iter - Copies datagrams from skb frags to an
+ *	iterator. If the iterator and skb frag point to the same page and
+ *	offset, then the copy is skipped.
+ *	@skb: buffer to copy
+ *	@offset: offset in the buffer to start copying from
+ *	@to: iovec iterator to copy to
+ *	@len: amount of data to copy from buffer to iovec
+ */
+int skb_ddp_copy_datagram_iter(const struct sk_buff *skb, int offset,
+			       struct iov_iter *to, int len)
+{
+	trace_skb_copy_datagram_iovec(skb, len);
+	return __skb_datagram_iter(skb, offset, to, len, false,
+			simple_ddp_copy_to_iter, NULL);
+}
+EXPORT_SYMBOL(skb_ddp_copy_datagram_iter);
+
 static size_t simple_copy_to_iter(const void *addr, size_t bytes,
 		void *data __always_unused, struct iov_iter *i)
 {
-- 
2.24.1



From borisp at mellanox.com  Thu Jan 14 10:10:15 2021
From: borisp at mellanox.com (Boris Pismenny)
Date: Thu, 14 Jan 2021 17:10:15 +0200
Subject: [PATCH v2 net-next 03/21] net: Introduce crc offload for tcp ddp ulp
In-Reply-To: <20210114151033.13020-1-borisp@mellanox.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
Message-ID: <20210114151033.13020-4-borisp@mellanox.com>

This commit introduces support for CRC offload to direct data placement
ULP on the receive side. Both DDP and CRC share a common API to
initialize the offload for a TCP socket. But otherwise, both can
be executed independently.

On the receive side, CRC offload requires a new SKB bit that
indicates that no CRC error was encountered while processing this packet.
If all packets of a ULP message have this bit set, then the CRC
verification for the message can be skipped, as hardware already checked
it.

The following patches will set and use this bit to perform NVME-TCP
CRC offload.

A subsequent series, will add NVMe-TCP transmit side CRC support.

Signed-off-by: Boris Pismenny <borisp at mellanox.com>
Signed-off-by: Ben Ben-Ishay <benishay at mellanox.com>
Signed-off-by: Or Gerlitz <ogerlitz at mellanox.com>
Signed-off-by: Yoray Zack <yorayz at mellanox.com>
Reviewed-by: Sagi Grimberg <sagi at grimberg.me>
---
 include/linux/netdev_features.h | 2 ++
 include/linux/skbuff.h          | 5 +++++
 net/Kconfig                     | 8 ++++++++
 net/ethtool/common.c            | 1 +
 net/ipv4/tcp_input.c            | 7 +++++++
 net/ipv4/tcp_ipv4.c             | 3 +++
 net/ipv4/tcp_offload.c          | 3 +++
 7 files changed, 29 insertions(+)

diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h
index fb35dcac03d2..dc79709586cd 100644
--- a/include/linux/netdev_features.h
+++ b/include/linux/netdev_features.h
@@ -85,6 +85,7 @@ enum {
 
 	NETIF_F_HW_MACSEC_BIT,		/* Offload MACsec operations */
 	NETIF_F_HW_TCP_DDP_BIT,		/* TCP direct data placement offload */
+	NETIF_F_HW_TCP_DDP_CRC_RX_BIT,	/* TCP DDP CRC RX offload */
 
 	/*
 	 * Add your fresh new feature above and remember to update
@@ -159,6 +160,7 @@ enum {
 #define NETIF_F_GSO_FRAGLIST	__NETIF_F(GSO_FRAGLIST)
 #define NETIF_F_HW_MACSEC	__NETIF_F(HW_MACSEC)
 #define NETIF_F_HW_TCP_DDP	__NETIF_F(HW_TCP_DDP)
+#define NETIF_F_HW_TCP_DDP_CRC_RX	__NETIF_F(HW_TCP_DDP_CRC_RX)
 
 /* Finds the next feature with the highest number of the range of start till 0.
  */
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 333bcdc39635..a841bc974452 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -683,6 +683,7 @@ typedef unsigned char *sk_buff_data_t;
  *		CHECKSUM_UNNECESSARY (max 3)
  *	@dst_pending_confirm: need to confirm neighbour
  *	@decrypted: Decrypted SKB
+ *	@ddp_crc: NIC is responsible for PDU's CRC computation and verification
  *	@napi_id: id of the NAPI struct this skb came from
  *	@sender_cpu: (aka @napi_id) source CPU in XPS
  *	@secmark: security marking
@@ -859,6 +860,10 @@ struct sk_buff {
 #ifdef CONFIG_TLS_DEVICE
 	__u8			decrypted:1;
 #endif
+#ifdef CONFIG_TCP_DDP_CRC
+	__u8                    ddp_crc:1;
+#endif
+
 
 #ifdef CONFIG_NET_SCHED
 	__u16			tc_index;	/* traffic control index */
diff --git a/net/Kconfig b/net/Kconfig
index 3876861cdc90..80ed9f038968 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -465,6 +465,14 @@ config TCP_DDP
 	  NVMe-TCP/iSCSI, to request the NIC to place TCP payload data
 	  of a command response directly into kernel pages.
 
+config TCP_DDP_CRC
+	bool "TCP direct data placement CRC offload"
+	default n
+	help
+	  Direct Data Placement (DDP) CRC32C offload for TCP enables ULP, such as
+	  NVMe-TCP/iSCSI, to request the NIC to calculate/verify the data digest
+	  of commands as they go through the NIC. Thus avoiding the costly
+	  per-byte overhead.
 
 endif   # if NET
 
diff --git a/net/ethtool/common.c b/net/ethtool/common.c
index a2ff7a4a6bbf..cc6858105449 100644
--- a/net/ethtool/common.c
+++ b/net/ethtool/common.c
@@ -69,6 +69,7 @@ const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] = {
 	[NETIF_F_GRO_FRAGLIST_BIT] =	 "rx-gro-list",
 	[NETIF_F_HW_MACSEC_BIT] =	 "macsec-hw-offload",
 	[NETIF_F_HW_TCP_DDP_BIT] =	 "tcp-ddp-offload",
+	[NETIF_F_HW_TCP_DDP_CRC_RX_BIT] =	 "tcp-ddp-crc-rx-offload",
 };
 
 const char
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index c7e16b0ed791..090c695e18b8 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5147,6 +5147,9 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list, struct rb_root *root,
 		memcpy(nskb->cb, skb->cb, sizeof(skb->cb));
 #ifdef CONFIG_TLS_DEVICE
 		nskb->decrypted = skb->decrypted;
+#endif
+#ifdef CONFIG_TCP_DDP_CRC
+		nskb->ddp_crc = skb->ddp_crc;
 #endif
 		TCP_SKB_CB(nskb)->seq = TCP_SKB_CB(nskb)->end_seq = start;
 		if (list)
@@ -5180,6 +5183,10 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list, struct rb_root *root,
 #ifdef CONFIG_TLS_DEVICE
 				if (skb->decrypted != nskb->decrypted)
 					goto end;
+#endif
+#ifdef CONFIG_TCP_DDP_CRC
+				if (skb->ddp_crc != nskb->ddp_crc)
+					goto end;
 #endif
 			}
 		}
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 58207c7769d0..64ccaf08fb3a 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1815,6 +1815,9 @@ bool tcp_add_backlog(struct sock *sk, struct sk_buff *skb)
 	      TCP_SKB_CB(skb)->tcp_flags) & (TCPHDR_ECE | TCPHDR_CWR)) ||
 #ifdef CONFIG_TLS_DEVICE
 	    tail->decrypted != skb->decrypted ||
+#endif
+#ifdef CONFIG_TCP_DDP_CRC
+	    tail->ddp_crc != skb->ddp_crc ||
 #endif
 	    thtail->doff != th->doff ||
 	    memcmp(thtail + 1, th + 1, hdrlen - sizeof(*th)))
diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c
index e09147ac9a99..39f5f0bcf181 100644
--- a/net/ipv4/tcp_offload.c
+++ b/net/ipv4/tcp_offload.c
@@ -262,6 +262,9 @@ struct sk_buff *tcp_gro_receive(struct list_head *head, struct sk_buff *skb)
 #ifdef CONFIG_TLS_DEVICE
 	flush |= p->decrypted ^ skb->decrypted;
 #endif
+#ifdef CONFIG_TCP_DDP_CRC
+	flush |= p->ddp_crc ^ skb->ddp_crc;
+#endif
 
 	if (flush || skb_gro_receive(p, skb)) {
 		mss = 1;
-- 
2.24.1



From borisp at mellanox.com  Thu Jan 14 10:10:20 2021
From: borisp at mellanox.com (Boris Pismenny)
Date: Thu, 14 Jan 2021 17:10:20 +0200
Subject: [PATCH v2 net-next 08/21] nvme-tcp : Recalculate crc in the end of
 the capsule
In-Reply-To: <20210114151033.13020-1-borisp@mellanox.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
Message-ID: <20210114151033.13020-9-borisp@mellanox.com>

From: Ben Ben-ishay <benishay at nvidia.com>

crc offload of the nvme capsule. Check if all the skb bits
are on, and if not recalculate the crc in SW and check it.

This patch reworks the receive-side crc calculation to always
run at the end, so as to keep a single flow for both offload
and non-offload. This change simplifies the code, but it may degrade
performance for non-offload crc calculation.

Signed-off-by: Boris Pismenny <borisp at mellanox.com>
Signed-off-by: Ben Ben-Ishay <benishay at mellanox.com>
Signed-off-by: Or Gerlitz <ogerlitz at mellanox.com>
Signed-off-by: Yoray Zack <yorayz at mellanox.com>
---
 drivers/nvme/host/tcp.c | 116 ++++++++++++++++++++++++++++++++--------
 1 file changed, 94 insertions(+), 22 deletions(-)

diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 9a43bd31ec15..09d2e2e529cd 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -69,6 +69,7 @@ enum nvme_tcp_queue_flags {
 	NVME_TCP_Q_LIVE		= 1,
 	NVME_TCP_Q_POLLING	= 2,
 	NVME_TCP_Q_OFF_DDP	= 3,
+	NVME_TCP_Q_OFF_DDGST_RX = 4,
 };
 
 enum nvme_tcp_recv_state {
@@ -95,6 +96,7 @@ struct nvme_tcp_queue {
 	size_t			data_remaining;
 	size_t			ddgst_remaining;
 	unsigned int		nr_cqe;
+	bool			ddgst_valid;
 
 	/* send state */
 	struct nvme_tcp_request *request;
@@ -233,6 +235,55 @@ static inline size_t nvme_tcp_pdu_last_send(struct nvme_tcp_request *req,
 	return nvme_tcp_pdu_data_left(req) <= len;
 }
 
+static inline bool nvme_tcp_ddp_ddgst_ok(struct nvme_tcp_queue *queue)
+{
+	return queue->ddgst_valid;
+}
+
+static inline void nvme_tcp_ddp_ddgst_update(struct nvme_tcp_queue *queue,
+					     struct sk_buff *skb)
+{
+	if (queue->ddgst_valid)
+#ifdef CONFIG_TCP_DDP_CRC
+		queue->ddgst_valid = skb->ddp_crc;
+#else
+		queue->ddgst_valid = false;
+#endif
+}
+
+static int nvme_tcp_req_map_sg(struct nvme_tcp_request *req, struct request *rq)
+{
+	int ret;
+
+	req->ddp.sg_table.sgl = req->ddp.first_sgl;
+	ret = sg_alloc_table_chained(&req->ddp.sg_table, blk_rq_nr_phys_segments(rq),
+				     req->ddp.sg_table.sgl, SG_CHUNK_SIZE);
+	if (ret)
+		return -ENOMEM;
+	req->ddp.nents = blk_rq_map_sg(rq->q, rq, req->ddp.sg_table.sgl);
+	return 0;
+}
+
+static void nvme_tcp_ddp_ddgst_recalc(struct ahash_request *hash,
+				      struct request *rq)
+{
+	struct nvme_tcp_request *req;
+
+	if (!rq)
+		return;
+
+	req = blk_mq_rq_to_pdu(rq);
+
+	if (!req->offloaded && nvme_tcp_req_map_sg(req, rq))
+		return;
+
+	crypto_ahash_init(hash);
+	req->ddp.sg_table.sgl = req->ddp.first_sgl;
+	ahash_request_set_crypt(hash, req->ddp.sg_table.sgl, NULL,
+				le32_to_cpu(req->data_len));
+	crypto_ahash_update(hash);
+}
+
 #ifdef CONFIG_TCP_DDP
 
 static bool nvme_tcp_resync_request(struct sock *sk, u32 seq, u32 flags);
@@ -289,12 +340,9 @@ int nvme_tcp_setup_ddp(struct nvme_tcp_queue *queue,
 	}
 
 	req->ddp.command_id = command_id;
-	req->ddp.sg_table.sgl = req->ddp.first_sgl;
-	ret = sg_alloc_table_chained(&req->ddp.sg_table, blk_rq_nr_phys_segments(rq),
-				     req->ddp.sg_table.sgl, SG_CHUNK_SIZE);
+	ret = nvme_tcp_req_map_sg(req, rq);
 	if (ret)
 		return -ENOMEM;
-	req->ddp.nents = blk_rq_map_sg(rq->q, rq, req->ddp.sg_table.sgl);
 
 	ret = netdev->tcp_ddp_ops->tcp_ddp_setup(netdev,
 						 queue->sock->sk,
@@ -316,7 +364,7 @@ int nvme_tcp_offload_socket(struct nvme_tcp_queue *queue)
 		return -ENODEV;
 	}
 
-	if (!(netdev->features & NETIF_F_HW_TCP_DDP)) {
+	if (!(netdev->features & (NETIF_F_HW_TCP_DDP | NETIF_F_HW_TCP_DDP_CRC_RX))) {
 		dev_put(netdev);
 		return -EOPNOTSUPP;
 	}
@@ -344,6 +392,9 @@ int nvme_tcp_offload_socket(struct nvme_tcp_queue *queue)
 	if (netdev->features & NETIF_F_HW_TCP_DDP)
 		set_bit(NVME_TCP_Q_OFF_DDP, &queue->flags);
 
+	if (netdev->features & NETIF_F_HW_TCP_DDP_CRC_RX)
+		set_bit(NVME_TCP_Q_OFF_DDGST_RX, &queue->flags);
+
 	return ret;
 }
 
@@ -375,7 +426,7 @@ int nvme_tcp_offload_limits(struct nvme_tcp_queue *queue)
 		return -ENODEV;
 	}
 
-	if (netdev->features & NETIF_F_HW_TCP_DDP &&
+	if ((netdev->features & (NETIF_F_HW_TCP_DDP | NETIF_F_HW_TCP_DDP_CRC_RX)) &&
 	    netdev->tcp_ddp_ops &&
 	    netdev->tcp_ddp_ops->tcp_ddp_limits)
 		ret = netdev->tcp_ddp_ops->tcp_ddp_limits(netdev, &limits);
@@ -727,6 +778,7 @@ static void nvme_tcp_init_recv_ctx(struct nvme_tcp_queue *queue)
 	queue->pdu_offset = 0;
 	queue->data_remaining = -1;
 	queue->ddgst_remaining = 0;
+	queue->ddgst_valid = true;
 }
 
 static void nvme_tcp_error_recovery(struct nvme_ctrl *ctrl)
@@ -907,7 +959,8 @@ static int nvme_tcp_recv_pdu(struct nvme_tcp_queue *queue, struct sk_buff *skb,
 
 	u64 pdu_seq = TCP_SKB_CB(skb)->seq + *offset - queue->pdu_offset;
 
-	if (test_bit(NVME_TCP_Q_OFF_DDP, &queue->flags))
+	if (test_bit(NVME_TCP_Q_OFF_DDP, &queue->flags) ||
+	    test_bit(NVME_TCP_Q_OFF_DDGST_RX, &queue->flags))
 		nvme_tcp_resync_response(queue, pdu_seq);
 
 	ret = skb_copy_bits(skb, *offset,
@@ -976,6 +1029,8 @@ static int nvme_tcp_recv_data(struct nvme_tcp_queue *queue, struct sk_buff *skb,
 	struct nvme_tcp_request *req;
 	struct request *rq;
 
+	if (queue->data_digest && test_bit(NVME_TCP_Q_OFF_DDGST_RX, &queue->flags))
+		nvme_tcp_ddp_ddgst_update(queue, skb);
 	rq = blk_mq_tag_to_rq(nvme_tcp_tagset(queue), pdu->command_id);
 	if (!rq) {
 		dev_err(queue->ctrl->ctrl.device,
@@ -1013,15 +1068,17 @@ static int nvme_tcp_recv_data(struct nvme_tcp_queue *queue, struct sk_buff *skb,
 		recv_len = min_t(size_t, recv_len,
 				iov_iter_count(&req->iter));
 
-		if (test_bit(NVME_TCP_Q_OFF_DDP, &queue->flags)) {
-			if (queue->data_digest)
+		if (test_bit(NVME_TCP_Q_OFF_DDP, &queue->flags)) { 
+			if (queue->data_digest &&
+			    !test_bit(NVME_TCP_Q_OFF_DDGST_RX, &queue->flags))
 				ret = skb_ddp_copy_and_hash_datagram_iter(skb, *offset,
 						&req->iter, recv_len, queue->rcv_hash);
 			else
 				ret = skb_ddp_copy_datagram_iter(skb, *offset,
 						&req->iter, recv_len);
 		} else {
-			if (queue->data_digest)
+			if (queue->data_digest &&
+			    !test_bit(NVME_TCP_Q_OFF_DDGST_RX, &queue->flags))
 				ret = skb_copy_and_hash_datagram_iter(skb, *offset,
 						&req->iter, recv_len, queue->rcv_hash);
 			else
@@ -1043,7 +1100,6 @@ static int nvme_tcp_recv_data(struct nvme_tcp_queue *queue, struct sk_buff *skb,
 
 	if (!queue->data_remaining) {
 		if (queue->data_digest) {
-			nvme_tcp_ddgst_final(queue->rcv_hash, &queue->exp_ddgst);
 			queue->ddgst_remaining = NVME_TCP_DIGEST_LENGTH;
 		} else {
 			if (pdu->hdr.flags & NVME_TCP_F_DATA_SUCCESS) {
@@ -1064,8 +1120,12 @@ static int nvme_tcp_recv_ddgst(struct nvme_tcp_queue *queue,
 	char *ddgst = (char *)&queue->recv_ddgst;
 	size_t recv_len = min_t(size_t, *len, queue->ddgst_remaining);
 	off_t off = NVME_TCP_DIGEST_LENGTH - queue->ddgst_remaining;
+	bool offload_fail, offload_en;
+	struct request *rq = NULL;
 	int ret;
 
+	if (test_bit(NVME_TCP_Q_OFF_DDGST_RX, &queue->flags))
+		nvme_tcp_ddp_ddgst_update(queue, skb);
 	ret = skb_copy_bits(skb, *offset, &ddgst[off], recv_len);
 	if (unlikely(ret))
 		return ret;
@@ -1076,17 +1136,29 @@ static int nvme_tcp_recv_ddgst(struct nvme_tcp_queue *queue,
 	if (queue->ddgst_remaining)
 		return 0;
 
-	if (queue->recv_ddgst != queue->exp_ddgst) {
-		dev_err(queue->ctrl->ctrl.device,
-			"data digest error: recv %#x expected %#x\n",
-			le32_to_cpu(queue->recv_ddgst),
-			le32_to_cpu(queue->exp_ddgst));
-		return -EIO;
+	offload_fail = !nvme_tcp_ddp_ddgst_ok(queue);
+	offload_en = test_bit(NVME_TCP_Q_OFF_DDGST_RX, &queue->flags);
+	if (!offload_en || offload_fail) {
+		if (offload_en && offload_fail) { // software-fallback
+			rq = blk_mq_tag_to_rq(nvme_tcp_tagset(queue),
+					      pdu->command_id);
+			nvme_tcp_ddp_ddgst_recalc(queue->rcv_hash, rq);
+		}
+
+		nvme_tcp_ddgst_final(queue->rcv_hash, &queue->exp_ddgst);
+		if (queue->recv_ddgst != queue->exp_ddgst) {
+			dev_err(queue->ctrl->ctrl.device,
+				"data digest error: recv %#x expected %#x\n",
+				le32_to_cpu(queue->recv_ddgst),
+				le32_to_cpu(queue->exp_ddgst));
+			return -EIO;
+		}
 	}
 
 	if (pdu->hdr.flags & NVME_TCP_F_DATA_SUCCESS) {
-		struct request *rq = blk_mq_tag_to_rq(nvme_tcp_tagset(queue),
-						pdu->command_id);
+		if (!rq)
+			rq = blk_mq_tag_to_rq(nvme_tcp_tagset(queue),
+					      pdu->command_id);
 
 		nvme_tcp_end_request(rq, NVME_SC_SUCCESS);
 		queue->nr_cqe++;
@@ -1825,8 +1897,10 @@ static void __nvme_tcp_stop_queue(struct nvme_tcp_queue *queue)
 	nvme_tcp_restore_sock_calls(queue);
 	cancel_work_sync(&queue->io_work);
 
-	if (test_bit(NVME_TCP_Q_OFF_DDP, &queue->flags))
+	if (test_bit(NVME_TCP_Q_OFF_DDP, &queue->flags) ||
+	    test_bit(NVME_TCP_Q_OFF_DDGST_RX, &queue->flags))
 		nvme_tcp_unoffload_socket(queue);
+
 }
 
 static void nvme_tcp_stop_queue(struct nvme_ctrl *nctrl, int qid)
@@ -1953,8 +2027,6 @@ static int nvme_tcp_alloc_admin_queue(struct nvme_ctrl *ctrl)
 {
 	int ret;
 
-	to_tcp_ctrl(ctrl)->offloading_netdev = NULL;
-
 	ret = nvme_tcp_alloc_queue(ctrl, 0, NVME_AQ_DEPTH);
 	if (ret)
 		return ret;
-- 
2.24.1



From borisp at mellanox.com  Thu Jan 14 10:10:19 2021
From: borisp at mellanox.com (Boris Pismenny)
Date: Thu, 14 Jan 2021 17:10:19 +0200
Subject: [PATCH v2 net-next 07/21] nvme-tcp: Add DDP data-path
In-Reply-To: <20210114151033.13020-1-borisp@mellanox.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
Message-ID: <20210114151033.13020-8-borisp@mellanox.com>

Introduce the NVMe-TCP DDP data-path offload.
Using this interface, the NIC hardware will scatter TCP payload directly
to the BIO pages according to the command_id in the PDU.
To maintain the correctness of the network stack, the driver is expected
to construct SKBs that point to the BIO pages.

The data-path interface contains two routines: tcp_ddp_setup/teardown.
The setup provides the mapping from command_id to the request buffers,
while the teardown removes this mapping.

For efficiency, we introduce an asynchronous nvme completion, which is
split between NVMe-TCP and the NIC driver as follows:
NVMe-TCP performs the specific completion, while NIC driver performs the
generic mq_blk completion.

Signed-off-by: Boris Pismenny <borisp at mellanox.com>
Signed-off-by: Ben Ben-Ishay <benishay at mellanox.com>
Signed-off-by: Or Gerlitz <ogerlitz at mellanox.com>
Signed-off-by: Yoray Zack <yorayz at mellanox.com>
---
 drivers/nvme/host/tcp.c | 141 +++++++++++++++++++++++++++++++++++++---
 1 file changed, 131 insertions(+), 10 deletions(-)

diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 31bf9e3ea236..9a43bd31ec15 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -57,6 +57,11 @@ struct nvme_tcp_request {
 	size_t			offset;
 	size_t			data_sent;
 	enum nvme_tcp_send_state state;
+
+	bool			offloaded;
+	struct tcp_ddp_io	ddp;
+	__le16			status;
+	union nvme_result	result;
 };
 
 enum nvme_tcp_queue_flags {
@@ -231,10 +236,74 @@ static inline size_t nvme_tcp_pdu_last_send(struct nvme_tcp_request *req,
 #ifdef CONFIG_TCP_DDP
 
 static bool nvme_tcp_resync_request(struct sock *sk, u32 seq, u32 flags);
+static void nvme_tcp_ddp_teardown_done(void *ddp_ctx);
 static const struct tcp_ddp_ulp_ops nvme_tcp_ddp_ulp_ops = {
 	.resync_request		= nvme_tcp_resync_request,
+	.ddp_teardown_done	= nvme_tcp_ddp_teardown_done,
 };
 
+static
+int nvme_tcp_teardown_ddp(struct nvme_tcp_queue *queue,
+			  u16 command_id,
+			  struct request *rq)
+{
+	struct nvme_tcp_request *req = blk_mq_rq_to_pdu(rq);
+	struct net_device *netdev = queue->ctrl->offloading_netdev;
+	int ret;
+
+	if (unlikely(!netdev)) {
+		pr_info_ratelimited("%s: netdev not found\n", __func__);
+		return -EINVAL;
+	}
+
+	ret = netdev->tcp_ddp_ops->tcp_ddp_teardown(netdev, queue->sock->sk,
+						    &req->ddp, rq);
+	sg_free_table_chained(&req->ddp.sg_table, SG_CHUNK_SIZE);
+	req->offloaded = false;
+	return ret;
+}
+
+static void nvme_tcp_ddp_teardown_done(void *ddp_ctx)
+{
+	struct request *rq = ddp_ctx;
+	struct nvme_tcp_request *req = blk_mq_rq_to_pdu(rq);
+
+	if (!nvme_try_complete_req(rq, cpu_to_le16(req->status << 1), req->result))
+		nvme_complete_rq(rq);
+}
+
+static
+int nvme_tcp_setup_ddp(struct nvme_tcp_queue *queue,
+		       u16 command_id,
+		       struct request *rq)
+{
+	struct nvme_tcp_request *req = blk_mq_rq_to_pdu(rq);
+	struct net_device *netdev = queue->ctrl->offloading_netdev;
+	int ret;
+
+	req->offloaded = false;
+
+	if (unlikely(!netdev)) {
+		pr_info_ratelimited("%s: netdev not found\n", __func__);
+		return -EINVAL;
+	}
+
+	req->ddp.command_id = command_id;
+	req->ddp.sg_table.sgl = req->ddp.first_sgl;
+	ret = sg_alloc_table_chained(&req->ddp.sg_table, blk_rq_nr_phys_segments(rq),
+				     req->ddp.sg_table.sgl, SG_CHUNK_SIZE);
+	if (ret)
+		return -ENOMEM;
+	req->ddp.nents = blk_rq_map_sg(rq->q, rq, req->ddp.sg_table.sgl);
+
+	ret = netdev->tcp_ddp_ops->tcp_ddp_setup(netdev,
+						 queue->sock->sk,
+						 &req->ddp);
+	if (!ret)
+		req->offloaded = true;
+	return ret;
+}
+
 static
 int nvme_tcp_offload_socket(struct nvme_tcp_queue *queue)
 {
@@ -375,6 +444,25 @@ bool nvme_tcp_resync_request(struct sock *sk, u32 seq, u32 flags)
 
 #else
 
+static
+int nvme_tcp_setup_ddp(struct nvme_tcp_queue *queue,
+		       u16 command_id,
+		       struct request *rq)
+{
+	return -EINVAL;
+}
+
+static
+int nvme_tcp_teardown_ddp(struct nvme_tcp_queue *queue,
+			  u16 command_id,
+			  struct request *rq)
+{
+	return -EINVAL;
+}
+
+static void nvme_tcp_ddp_teardown_done(void *ddp_ctx)
+{}
+
 static
 int nvme_tcp_offload_socket(struct nvme_tcp_queue *queue)
 {
@@ -653,6 +741,7 @@ static void nvme_tcp_error_recovery(struct nvme_ctrl *ctrl)
 static int nvme_tcp_process_nvme_cqe(struct nvme_tcp_queue *queue,
 		struct nvme_completion *cqe)
 {
+	struct nvme_tcp_request *req;
 	struct request *rq;
 
 	rq = blk_mq_tag_to_rq(nvme_tcp_tagset(queue), cqe->command_id);
@@ -664,8 +753,15 @@ static int nvme_tcp_process_nvme_cqe(struct nvme_tcp_queue *queue,
 		return -EINVAL;
 	}
 
-	if (!nvme_try_complete_req(rq, cqe->status, cqe->result))
-		nvme_complete_rq(rq);
+	req = blk_mq_rq_to_pdu(rq);
+	if (req->offloaded) {
+		req->status = cqe->status;
+		req->result = cqe->result;
+		nvme_tcp_teardown_ddp(queue, cqe->command_id, rq);
+	} else {
+		if (!nvme_try_complete_req(rq, cqe->status, cqe->result))
+			nvme_complete_rq(rq);
+	}
 	queue->nr_cqe++;
 
 	return 0;
@@ -859,9 +955,18 @@ static int nvme_tcp_recv_pdu(struct nvme_tcp_queue *queue, struct sk_buff *skb,
 static inline void nvme_tcp_end_request(struct request *rq, u16 status)
 {
 	union nvme_result res = {};
+	struct nvme_tcp_request *req = blk_mq_rq_to_pdu(rq);
+	struct nvme_tcp_queue *queue = req->queue;
+	struct nvme_tcp_data_pdu *pdu = (void *)queue->pdu;
 
-	if (!nvme_try_complete_req(rq, cpu_to_le16(status << 1), res))
-		nvme_complete_rq(rq);
+	if (req->offloaded) {
+		req->status = cpu_to_le16(status << 1);
+		req->result = res;
+		nvme_tcp_teardown_ddp(queue, pdu->command_id, rq);
+	} else {
+		if (!nvme_try_complete_req(rq, cpu_to_le16(status << 1), res))
+			nvme_complete_rq(rq);
+	}
 }
 
 static int nvme_tcp_recv_data(struct nvme_tcp_queue *queue, struct sk_buff *skb,
@@ -908,12 +1013,22 @@ static int nvme_tcp_recv_data(struct nvme_tcp_queue *queue, struct sk_buff *skb,
 		recv_len = min_t(size_t, recv_len,
 				iov_iter_count(&req->iter));
 
-		if (queue->data_digest)
-			ret = skb_copy_and_hash_datagram_iter(skb, *offset,
-				&req->iter, recv_len, queue->rcv_hash);
-		else
-			ret = skb_copy_datagram_iter(skb, *offset,
-					&req->iter, recv_len);
+		if (test_bit(NVME_TCP_Q_OFF_DDP, &queue->flags)) {
+			if (queue->data_digest)
+				ret = skb_ddp_copy_and_hash_datagram_iter(skb, *offset,
+						&req->iter, recv_len, queue->rcv_hash);
+			else
+				ret = skb_ddp_copy_datagram_iter(skb, *offset,
+						&req->iter, recv_len);
+		} else {
+			if (queue->data_digest)
+				ret = skb_copy_and_hash_datagram_iter(skb, *offset,
+						&req->iter, recv_len, queue->rcv_hash);
+			else
+				ret = skb_copy_datagram_iter(skb, *offset,
+						&req->iter, recv_len);
+		}
+
 		if (ret) {
 			dev_err(queue->ctrl->ctrl.device,
 				"queue %d failed to copy request %#x data",
@@ -1137,6 +1252,7 @@ static int nvme_tcp_try_send_cmd_pdu(struct nvme_tcp_request *req)
 	bool inline_data = nvme_tcp_has_inline_data(req);
 	u8 hdgst = nvme_tcp_hdgst_len(queue);
 	int len = sizeof(*pdu) + hdgst - req->offset;
+	struct request *rq = blk_mq_rq_from_pdu(req);
 	int flags = MSG_DONTWAIT;
 	int ret;
 
@@ -1145,6 +1261,10 @@ static int nvme_tcp_try_send_cmd_pdu(struct nvme_tcp_request *req)
 	else
 		flags |= MSG_EOR;
 
+	if (test_bit(NVME_TCP_Q_OFF_DDP, &queue->flags) &&
+	    blk_rq_nr_phys_segments(rq) && rq_data_dir(rq) == READ)
+		nvme_tcp_setup_ddp(queue, pdu->cmd.common.command_id, rq);
+
 	if (queue->hdr_digest && !req->offset)
 		nvme_tcp_hdgst(queue->snd_hash, pdu, sizeof(*pdu));
 
@@ -2447,6 +2567,7 @@ static blk_status_t nvme_tcp_setup_cmd_pdu(struct nvme_ns *ns,
 	req->data_len = blk_rq_nr_phys_segments(rq) ?
 				blk_rq_payload_bytes(rq) : 0;
 	req->curr_bio = rq->bio;
+	req->offloaded = false;
 
 	if (rq_data_dir(rq) == WRITE &&
 	    req->data_len <= nvme_tcp_inline_data_size(queue))
-- 
2.24.1



From borisp at mellanox.com  Thu Jan 14 10:10:18 2021
From: borisp at mellanox.com (Boris Pismenny)
Date: Thu, 14 Jan 2021 17:10:18 +0200
Subject: [PATCH v2 net-next 06/21] nvme-tcp: Add DDP offload control path
In-Reply-To: <20210114151033.13020-1-borisp@mellanox.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
Message-ID: <20210114151033.13020-7-borisp@mellanox.com>

This commit introduces direct data placement offload to NVME
TCP. There is a context per queue, which is established after the
handshake using the tcp_ddp_sk_add/del NDOs.

Additionally, a resynchronization routine is used to assist
hardware recovery from TCP OOO, and continue the offload.
Resynchronization operates as follows:

1. TCP OOO causes the NIC HW to stop the offload

2. NIC HW identifies a PDU header at some TCP sequence number,
and asks NVMe-TCP to confirm it.
This request is delivered from the NIC driver to NVMe-TCP by first
finding the socket for the packet that triggered the request, and
then finding the nvme_tcp_queue that is used by this routine.
Finally, the request is recorded in the nvme_tcp_queue.

3. When NVMe-TCP observes the requested TCP sequence, it will compare
it with the PDU header TCP sequence, and report the result to the
NIC driver (tcp_ddp_resync), which will update the HW,
and resume offload when all is successful.

Furthermore, we let the offloading driver advertise what is the max hw
sectors/segments via tcp_ddp_limits.

A follow-up patch introduces the data-path changes required for this
offload.

Signed-off-by: Boris Pismenny <borisp at mellanox.com>
Signed-off-by: Ben Ben-Ishay <benishay at mellanox.com>
Signed-off-by: Or Gerlitz <ogerlitz at mellanox.com>
Signed-off-by: Yoray Zack <yorayz at mellanox.com>
---
 drivers/nvme/host/tcp.c | 199 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 197 insertions(+), 2 deletions(-)

diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 1ba659927442..31bf9e3ea236 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -14,6 +14,7 @@
 #include <linux/blk-mq.h>
 #include <crypto/hash.h>
 #include <net/busy_poll.h>
+#include <net/tcp_ddp.h>
 
 #include "nvme.h"
 #include "fabrics.h"
@@ -62,6 +63,7 @@ enum nvme_tcp_queue_flags {
 	NVME_TCP_Q_ALLOCATED	= 0,
 	NVME_TCP_Q_LIVE		= 1,
 	NVME_TCP_Q_POLLING	= 2,
+	NVME_TCP_Q_OFF_DDP	= 3,
 };
 
 enum nvme_tcp_recv_state {
@@ -110,6 +112,8 @@ struct nvme_tcp_queue {
 	void (*state_change)(struct sock *);
 	void (*data_ready)(struct sock *);
 	void (*write_space)(struct sock *);
+
+	atomic64_t  resync_req;
 };
 
 struct nvme_tcp_ctrl {
@@ -128,6 +132,8 @@ struct nvme_tcp_ctrl {
 	struct delayed_work	connect_work;
 	struct nvme_tcp_request async_req;
 	u32			io_queues[HCTX_MAX_TYPES];
+
+	struct net_device       *offloading_netdev;
 };
 
 static LIST_HEAD(nvme_tcp_ctrl_list);
@@ -222,6 +228,182 @@ static inline size_t nvme_tcp_pdu_last_send(struct nvme_tcp_request *req,
 	return nvme_tcp_pdu_data_left(req) <= len;
 }
 
+#ifdef CONFIG_TCP_DDP
+
+static bool nvme_tcp_resync_request(struct sock *sk, u32 seq, u32 flags);
+static const struct tcp_ddp_ulp_ops nvme_tcp_ddp_ulp_ops = {
+	.resync_request		= nvme_tcp_resync_request,
+};
+
+static
+int nvme_tcp_offload_socket(struct nvme_tcp_queue *queue)
+{
+	struct net_device *netdev = get_netdev_for_sock(queue->sock->sk, true);
+	struct nvme_tcp_ddp_config config = {};
+	int ret;
+
+	if (!netdev) {
+		dev_info_ratelimited(queue->ctrl->ctrl.device, "netdev not found\n");
+		return -ENODEV;
+	}
+
+	if (!(netdev->features & NETIF_F_HW_TCP_DDP)) {
+		dev_put(netdev);
+		return -EOPNOTSUPP;
+	}
+
+	config.cfg.type		= TCP_DDP_NVME;
+	config.pfv		= NVME_TCP_PFV_1_0;
+	config.cpda		= 0;
+	config.dgst		= queue->hdr_digest ?
+		NVME_TCP_HDR_DIGEST_ENABLE : 0;
+	config.dgst		|= queue->data_digest ?
+		NVME_TCP_DATA_DIGEST_ENABLE : 0;
+	config.queue_size	= queue->queue_size;
+	config.queue_id		= nvme_tcp_queue_id(queue);
+	config.io_cpu		= queue->io_cpu;
+
+	ret = netdev->tcp_ddp_ops->tcp_ddp_sk_add(netdev,
+						  queue->sock->sk,
+						  (struct tcp_ddp_config *)&config);
+	if (ret) {
+		dev_put(netdev);
+		return ret;
+	}
+
+	inet_csk(queue->sock->sk)->icsk_ulp_ddp_ops = &nvme_tcp_ddp_ulp_ops;
+	if (netdev->features & NETIF_F_HW_TCP_DDP)
+		set_bit(NVME_TCP_Q_OFF_DDP, &queue->flags);
+
+	return ret;
+}
+
+static
+void nvme_tcp_unoffload_socket(struct nvme_tcp_queue *queue)
+{
+	struct net_device *netdev = queue->ctrl->offloading_netdev;
+
+	if (!netdev) {
+		dev_info_ratelimited(queue->ctrl->ctrl.device, "netdev not found\n");
+		return;
+	}
+
+	netdev->tcp_ddp_ops->tcp_ddp_sk_del(netdev, queue->sock->sk);
+
+	inet_csk(queue->sock->sk)->icsk_ulp_ddp_ops = NULL;
+	dev_put(netdev); /* put the queue_init get_netdev_for_sock() */
+}
+
+static
+int nvme_tcp_offload_limits(struct nvme_tcp_queue *queue)
+{
+	struct net_device *netdev = get_netdev_for_sock(queue->sock->sk, true);
+	struct tcp_ddp_limits limits;
+	int ret = 0;
+
+	if (!netdev) {
+		dev_info_ratelimited(queue->ctrl->ctrl.device, "netdev not found\n");
+		return -ENODEV;
+	}
+
+	if (netdev->features & NETIF_F_HW_TCP_DDP &&
+	    netdev->tcp_ddp_ops &&
+	    netdev->tcp_ddp_ops->tcp_ddp_limits)
+		ret = netdev->tcp_ddp_ops->tcp_ddp_limits(netdev, &limits);
+	else
+		ret = -EOPNOTSUPP;
+
+	if (!ret) {
+		queue->ctrl->offloading_netdev = netdev;
+		dev_dbg_ratelimited(queue->ctrl->ctrl.device,
+				    "netdev %s offload limits: max_ddp_sgl_len %d\n",
+				    netdev->name, limits.max_ddp_sgl_len);
+		queue->ctrl->ctrl.max_segments = limits.max_ddp_sgl_len;
+		queue->ctrl->ctrl.max_hw_sectors =
+			limits.max_ddp_sgl_len << (ilog2(SZ_4K) - 9);
+	} else {
+		queue->ctrl->offloading_netdev = NULL;
+	}
+
+	dev_put(netdev);
+
+	return ret;
+}
+
+static
+void nvme_tcp_resync_response(struct nvme_tcp_queue *queue,
+			      unsigned int pdu_seq)
+{
+	struct net_device *netdev = queue->ctrl->offloading_netdev;
+	u64 resync_val;
+	u32 resync_seq;
+
+	resync_val = atomic64_read(&queue->resync_req);
+	/* Lower 32 bit flags. Check validity of the request */
+	if ((resync_val & TCP_DDP_RESYNC_REQ) == 0)
+		return;
+
+	/* Obtain and check requested sequence number: is this PDU header before the request? */
+	resync_seq = resync_val >> 32;
+	if (before(pdu_seq, resync_seq))
+		return;
+
+	if (unlikely(!netdev)) {
+		pr_info_ratelimited("%s: netdev not found\n", __func__);
+		return;
+	}
+
+	/**
+	 * The atomic operation gurarantees that we don't miss any NIC driver
+	 * resync requests submitted after the above checks.
+	 */
+	if (atomic64_cmpxchg(&queue->resync_req, resync_val,
+			     resync_val & ~TCP_DDP_RESYNC_REQ))
+		netdev->tcp_ddp_ops->tcp_ddp_resync(netdev, queue->sock->sk, pdu_seq);
+}
+
+static
+bool nvme_tcp_resync_request(struct sock *sk, u32 seq, u32 flags)
+{
+	struct nvme_tcp_queue *queue = sk->sk_user_data;
+
+	atomic64_set(&queue->resync_req,
+		     (((uint64_t)seq << 32) | flags));
+
+	return true;
+}
+
+#else
+
+static
+int nvme_tcp_offload_socket(struct nvme_tcp_queue *queue)
+{
+	return -EINVAL;
+}
+
+static
+void nvme_tcp_unoffload_socket(struct nvme_tcp_queue *queue)
+{}
+
+static
+int nvme_tcp_offload_limits(struct nvme_tcp_queue *queue)
+{
+	return -EINVAL;
+}
+
+static
+void nvme_tcp_resync_response(struct nvme_tcp_queue *queue,
+			      unsigned int pdu_seq)
+{}
+
+static
+bool nvme_tcp_resync_request(struct sock *sk, u32 seq, u32 flags)
+{
+	return false;
+}
+
+#endif
+
 static void nvme_tcp_init_iter(struct nvme_tcp_request *req,
 		unsigned int dir)
 {
@@ -627,6 +809,11 @@ static int nvme_tcp_recv_pdu(struct nvme_tcp_queue *queue, struct sk_buff *skb,
 	size_t rcv_len = min_t(size_t, *len, queue->pdu_remaining);
 	int ret;
 
+	u64 pdu_seq = TCP_SKB_CB(skb)->seq + *offset - queue->pdu_offset;
+
+	if (test_bit(NVME_TCP_Q_OFF_DDP, &queue->flags))
+		nvme_tcp_resync_response(queue, pdu_seq);
+
 	ret = skb_copy_bits(skb, *offset,
 		&pdu[queue->pdu_offset], rcv_len);
 	if (unlikely(ret))
@@ -1517,6 +1704,9 @@ static void __nvme_tcp_stop_queue(struct nvme_tcp_queue *queue)
 	kernel_sock_shutdown(queue->sock, SHUT_RDWR);
 	nvme_tcp_restore_sock_calls(queue);
 	cancel_work_sync(&queue->io_work);
+
+	if (test_bit(NVME_TCP_Q_OFF_DDP, &queue->flags))
+		nvme_tcp_unoffload_socket(queue);
 }
 
 static void nvme_tcp_stop_queue(struct nvme_ctrl *nctrl, int qid)
@@ -1534,10 +1724,13 @@ static int nvme_tcp_start_queue(struct nvme_ctrl *nctrl, int idx)
 	struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl);
 	int ret;
 
-	if (idx)
+	if (idx) {
 		ret = nvmf_connect_io_queue(nctrl, idx, false);
-	else
+		nvme_tcp_offload_socket(&ctrl->queues[idx]);
+	} else {
 		ret = nvmf_connect_admin_queue(nctrl);
+		nvme_tcp_offload_limits(&ctrl->queues[idx]);
+	}
 
 	if (!ret) {
 		set_bit(NVME_TCP_Q_LIVE, &ctrl->queues[idx].flags);
@@ -1640,6 +1833,8 @@ static int nvme_tcp_alloc_admin_queue(struct nvme_ctrl *ctrl)
 {
 	int ret;
 
+	to_tcp_ctrl(ctrl)->offloading_netdev = NULL;
+
 	ret = nvme_tcp_alloc_queue(ctrl, 0, NVME_AQ_DEPTH);
 	if (ret)
 		return ret;
-- 
2.24.1



From borisp at mellanox.com  Thu Jan 14 10:10:24 2021
From: borisp at mellanox.com (Boris Pismenny)
Date: Thu, 14 Jan 2021 17:10:24 +0200
Subject: [PATCH v2 net-next 12/21] net/mlx5e: TCP flow steering for nvme-tcp
In-Reply-To: <20210114151033.13020-1-borisp@mellanox.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
Message-ID: <20210114151033.13020-13-borisp@mellanox.com>

Both nvme-tcp and tls require tcp flow steering. Compile it for both of
them. Additionally, use reference counting to allocate/free TCP flow
steering.

Signed-off-by: Boris Pismenny <borisp at mellanox.com>
Signed-off-by: Ben Ben-Ishay <benishay at mellanox.com>
Signed-off-by: Or Gerlitz <ogerlitz at mellanox.com>
Signed-off-by: Yoray Zack <yorayz at mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/en/fs.h        |  4 ++--
 .../net/ethernet/mellanox/mlx5/core/en_accel/fs_tcp.c  | 10 ++++++++++
 .../net/ethernet/mellanox/mlx5/core/en_accel/fs_tcp.h  |  2 +-
 3 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/fs.h b/drivers/net/ethernet/mellanox/mlx5/core/en/fs.h
index a16297e7e2ac..a7fe3a6358ea 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/fs.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/fs.h
@@ -137,7 +137,7 @@ enum {
 	MLX5E_L2_FT_LEVEL,
 	MLX5E_TTC_FT_LEVEL,
 	MLX5E_INNER_TTC_FT_LEVEL,
-#ifdef CONFIG_MLX5_EN_TLS
+#if defined(CONFIG_MLX5_EN_TLS) || defined(CONFIG_MLX5_EN_NVMEOTCP)
 	MLX5E_ACCEL_FS_TCP_FT_LEVEL,
 #endif
 #ifdef CONFIG_MLX5_EN_ARFS
@@ -256,7 +256,7 @@ struct mlx5e_flow_steering {
 #ifdef CONFIG_MLX5_EN_ARFS
 	struct mlx5e_arfs_tables        arfs;
 #endif
-#ifdef CONFIG_MLX5_EN_TLS
+#if defined(CONFIG_MLX5_EN_TLS) || defined(CONFIG_MLX5_EN_NVMEOTCP)
 	struct mlx5e_accel_fs_tcp      *accel_tcp;
 #endif
 };
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/fs_tcp.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/fs_tcp.c
index e51f60b55daa..21341a92f355 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/fs_tcp.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/fs_tcp.c
@@ -14,6 +14,7 @@ enum accel_fs_tcp_type {
 struct mlx5e_accel_fs_tcp {
 	struct mlx5e_flow_table tables[ACCEL_FS_TCP_NUM_TYPES];
 	struct mlx5_flow_handle *default_rules[ACCEL_FS_TCP_NUM_TYPES];
+	refcount_t		ref_count;
 };
 
 static enum mlx5e_traffic_types fs_accel2tt(enum accel_fs_tcp_type i)
@@ -337,6 +338,7 @@ static int accel_fs_tcp_enable(struct mlx5e_priv *priv)
 			return err;
 		}
 	}
+	refcount_set(&priv->fs.accel_tcp->ref_count, 1);
 	return 0;
 }
 
@@ -360,6 +362,9 @@ void mlx5e_accel_fs_tcp_destroy(struct mlx5e_priv *priv)
 	if (!priv->fs.accel_tcp)
 		return;
 
+	if (!refcount_dec_and_test(&priv->fs.accel_tcp->ref_count))
+		return;
+
 	accel_fs_tcp_disable(priv);
 
 	for (i = 0; i < ACCEL_FS_TCP_NUM_TYPES; i++)
@@ -376,6 +381,11 @@ int mlx5e_accel_fs_tcp_create(struct mlx5e_priv *priv)
 	if (!MLX5_CAP_FLOWTABLE_NIC_RX(priv->mdev, ft_field_support.outer_ip_version))
 		return -EOPNOTSUPP;
 
+	if (priv->fs.accel_tcp) {
+		refcount_inc(&priv->fs.accel_tcp->ref_count);
+		return 0;
+	}
+
 	priv->fs.accel_tcp = kzalloc(sizeof(*priv->fs.accel_tcp), GFP_KERNEL);
 	if (!priv->fs.accel_tcp)
 		return -ENOMEM;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/fs_tcp.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/fs_tcp.h
index 589235824543..8aff9298183c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/fs_tcp.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/fs_tcp.h
@@ -6,7 +6,7 @@
 
 #include "en.h"
 
-#ifdef CONFIG_MLX5_EN_TLS
+#if defined(CONFIG_MLX5_EN_TLS) || defined(CONFIG_MLX5_EN_NVMEOTCP)
 int mlx5e_accel_fs_tcp_create(struct mlx5e_priv *priv);
 void mlx5e_accel_fs_tcp_destroy(struct mlx5e_priv *priv);
 struct mlx5_flow_handle *mlx5e_accel_fs_add_sk(struct mlx5e_priv *priv,
-- 
2.24.1



From borisp at mellanox.com  Thu Jan 14 10:10:29 2021
From: borisp at mellanox.com (Boris Pismenny)
Date: Thu, 14 Jan 2021 17:10:29 +0200
Subject: [PATCH v2 net-next 17/21] net/mlx5e: NVMEoTCP async ddp invalidation
In-Reply-To: <20210114151033.13020-1-borisp@mellanox.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
Message-ID: <20210114151033.13020-18-borisp@mellanox.com>

From: Ben Ben-Ishay <benishay at nvidia.com>

Teardown ddp contexts asynchronously by posting a WQE, and calling back
to nvme-tcp when the corresponding CQE is received.

Signed-off-by: Boris Pismenny <borisp at mellanox.com>
Signed-off-by: Ben Ben-Ishay <benishay at nvidia.com>
Signed-off-by: Or Gerlitz <ogerlitz at mellanox.com>
Signed-off-by: Yoray Zack <yorayz at mellanox.com>
---
 .../net/ethernet/mellanox/mlx5/core/en/txrx.h |  4 ++
 .../mellanox/mlx5/core/en_accel/nvmeotcp.c    | 66 ++++++++++++++++---
 .../mellanox/mlx5/core/en_accel/nvmeotcp.h    |  1 +
 .../net/ethernet/mellanox/mlx5/core/en_rx.c   |  6 ++
 4 files changed, 69 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h b/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
index f00d76f1ded4..eb929edabd6b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
@@ -36,6 +36,7 @@ enum mlx5e_icosq_wqe_type {
 #endif
 #ifdef CONFIG_MLX5_EN_NVMEOTCP
 	MLX5E_ICOSQ_WQE_UMR_NVME_TCP,
+	MLX5E_ICOSQ_WQE_UMR_NVME_TCP_INVALIDATE,
 	MLX5E_ICOSQ_WQE_SET_PSV_NVME_TCP,
 #endif
 };
@@ -184,6 +185,9 @@ struct mlx5e_icosq_wqe_info {
 		struct {
 			struct mlx5e_nvmeotcp_queue *queue;
 		} nvmeotcp_q;
+		struct {
+			struct nvmeotcp_queue_entry *entry;
+		} nvmeotcp_qe;
 #endif
 	};
 };
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.c
index 3a42477f1bd7..22fa1e9f3e7a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.c
@@ -152,6 +152,7 @@ enum wqe_type {
 	BSF_KLM_UMR = 1,
 	SET_PSV_UMR = 2,
 	BSF_UMR = 3,
+	KLM_INV_UMR = 4,
 };
 
 static void
@@ -208,6 +209,13 @@ build_nvmeotcp_klm_umr(struct mlx5e_nvmeotcp_queue *queue,
 				   MLX5E_KLM_UMR_DS_CNT(ALIGN(klm_entries, KLM_ALIGNMENT)));
 	cseg->general_id = cpu_to_be32(id);
 
+	if (!klm_entries) { /* this is invalidate */
+		ucseg->mkey_mask = cpu_to_be64(MLX5_MKEY_MASK_FREE);
+		ucseg->flags = MLX5_UMR_INLINE;
+		mkc->status = MLX5_MKEY_STATUS_FREE;
+		return;
+	}
+
 	if (klm_type == KLM_UMR && !klm_offset) {
 		ucseg->mkey_mask |= cpu_to_be64(MLX5_MKEY_MASK_XLT_OCT_SIZE |
 						MLX5_MKEY_MASK_LEN | MLX5_MKEY_MASK_FREE);
@@ -306,8 +314,8 @@ build_nvmeotcp_static_params(struct mlx5e_nvmeotcp_queue *queue,
 
 static void
 mlx5e_nvmeotcp_fill_wi(struct mlx5e_nvmeotcp_queue *nvmeotcp_queue,
-		       struct mlx5e_icosq *sq, u32 wqe_bbs, u16 pi,
-		       enum wqe_type type)
+		       struct mlx5e_icosq *sq, u32 wqe_bbs,
+		       u16 pi, u16 ccid, enum wqe_type type)
 {
 	struct mlx5e_icosq_wqe_info *wi = &sq->db.wqe_info[pi];
 
@@ -316,12 +324,17 @@ mlx5e_nvmeotcp_fill_wi(struct mlx5e_nvmeotcp_queue *nvmeotcp_queue,
 	case SET_PSV_UMR:
 		wi->wqe_type = MLX5E_ICOSQ_WQE_SET_PSV_NVME_TCP;
 		break;
+	case KLM_INV_UMR:
+		wi->wqe_type = MLX5E_ICOSQ_WQE_UMR_NVME_TCP_INVALIDATE;
+		break;
 	default:
 		wi->wqe_type = MLX5E_ICOSQ_WQE_UMR_NVME_TCP;
 		break;
 	}
 
-	if (type == SET_PSV_UMR)
+	if (type == KLM_INV_UMR)
+		wi->nvmeotcp_qe.entry = &nvmeotcp_queue->ccid_table[ccid];
+	else if (type == SET_PSV_UMR)
 		wi->nvmeotcp_q.queue = nvmeotcp_queue;
 }
 
@@ -336,7 +349,7 @@ mlx5e_nvmeotcp_rx_post_static_params_wqe(struct mlx5e_nvmeotcp_queue *queue,
 	wqe_bbs = MLX5E_NVMEOTCP_STATIC_PARAMS_WQEBBS;
 	pi = mlx5e_icosq_get_next_pi(sq, wqe_bbs);
 	wqe = MLX5E_NVMEOTCP_FETCH_STATIC_PARAMS_WQE(sq, pi);
-	mlx5e_nvmeotcp_fill_wi(NULL, sq, wqe_bbs, pi, BSF_UMR);
+	mlx5e_nvmeotcp_fill_wi(NULL, sq, wqe_bbs, pi, 0, BSF_UMR);
 	build_nvmeotcp_static_params(queue, wqe, resync_seq, queue->zerocopy, queue->crc_rx);
 	sq->pc += wqe_bbs;
 	mlx5e_notify_hw(&sq->wq, sq->pc, sq->uar_map, &wqe->ctrl);
@@ -353,7 +366,7 @@ mlx5e_nvmeotcp_rx_post_progress_params_wqe(struct mlx5e_nvmeotcp_queue *queue,
 	wqe_bbs = MLX5E_NVMEOTCP_PROGRESS_PARAMS_WQEBBS;
 	pi = mlx5e_icosq_get_next_pi(sq, wqe_bbs);
 	wqe = MLX5E_NVMEOTCP_FETCH_PROGRESS_PARAMS_WQE(sq, pi);
-	mlx5e_nvmeotcp_fill_wi(queue, sq, wqe_bbs, pi, SET_PSV_UMR);
+	mlx5e_nvmeotcp_fill_wi(queue, sq, wqe_bbs, pi, 0, SET_PSV_UMR);
 	build_nvmeotcp_progress_params(queue, wqe, seq);
 	sq->pc += wqe_bbs;
 	mlx5e_notify_hw(&sq->wq, sq->pc, sq->uar_map, &wqe->ctrl);
@@ -377,7 +390,8 @@ post_klm_wqe(struct mlx5e_nvmeotcp_queue *queue,
 	wqe_bbs = DIV_ROUND_UP(wqe_sz, MLX5_SEND_WQE_BB);
 	pi = mlx5e_icosq_get_next_pi(sq, wqe_bbs);
 	wqe = MLX5E_NVMEOTCP_FETCH_KLM_WQE(sq, pi);
-	mlx5e_nvmeotcp_fill_wi(queue, sq, wqe_bbs, pi, wqe_type);
+	mlx5e_nvmeotcp_fill_wi(queue, sq, wqe_bbs, pi, ccid,
+			       klm_length ? KLM_UMR : KLM_INV_UMR);
 	build_nvmeotcp_klm_umr(queue, wqe, ccid, cur_klm_entries, *klm_offset,
 			       klm_length, wqe_type);
 	*klm_offset += cur_klm_entries;
@@ -395,8 +409,13 @@ mlx5e_nvmeotcp_post_klm_wqe(struct mlx5e_nvmeotcp_queue *queue,
 	struct mlx5e_icosq *sq = &queue->sq->icosq;
 
 	/* TODO: set stricter wqe_sz; using max for now */
-	wqes = DIV_ROUND_UP(klm_length, queue->max_klms_per_wqe);
-	wqe_sz = MLX5E_KLM_UMR_WQE_SZ(queue->max_klms_per_wqe);
+	if (klm_length == 0) {
+		wqes = 1;
+		wqe_sz = MLX5E_NVMEOTCP_STATIC_PARAMS_WQEBBS;
+	} else {
+		wqes = DIV_ROUND_UP(klm_length, queue->max_klms_per_wqe);
+		wqe_sz = MLX5E_KLM_UMR_WQE_SZ(queue->max_klms_per_wqe);
+	}
 
 	max_wqe_bbs = DIV_ROUND_UP(wqe_sz, MLX5_SEND_WQE_BB);
 
@@ -735,6 +754,24 @@ mlx5e_nvmeotcp_ddp_setup(struct net_device *netdev,
 	return 0;
 }
 
+void mlx5e_nvmeotcp_ddp_inv_done(struct mlx5e_icosq_wqe_info *wi)
+{
+	struct nvmeotcp_queue_entry *q_entry = wi->nvmeotcp_qe.entry;
+	struct mlx5e_nvmeotcp_queue *queue = q_entry->queue;
+	struct mlx5_core_dev *mdev = queue->priv->mdev;
+	struct tcp_ddp_io *ddp = q_entry->ddp;
+	const struct tcp_ddp_ulp_ops *ulp_ops;
+
+	dma_unmap_sg(mdev->device, ddp->sg_table.sgl,
+		     q_entry->sgl_length, DMA_FROM_DEVICE);
+
+	q_entry->sgl_length = 0;
+
+	ulp_ops = inet_csk(queue->sk)->icsk_ulp_ddp_ops;
+	if (ulp_ops && ulp_ops->ddp_teardown_done)
+		ulp_ops->ddp_teardown_done(q_entry->ddp_ctx);
+}
+
 void mlx5e_nvmeotcp_ctx_comp(struct mlx5e_icosq_wqe_info *wi)
 {
 	struct mlx5e_nvmeotcp_queue *queue = wi->nvmeotcp_q.queue;
@@ -751,6 +788,19 @@ mlx5e_nvmeotcp_ddp_teardown(struct net_device *netdev,
 			    struct tcp_ddp_io *ddp,
 			    void *ddp_ctx)
 {
+	struct mlx5e_nvmeotcp_queue *queue =
+		(struct mlx5e_nvmeotcp_queue *)tcp_ddp_get_ctx(sk);
+	struct mlx5e_priv *priv = netdev_priv(netdev);
+	struct nvmeotcp_queue_entry *q_entry;
+
+	q_entry  = &queue->ccid_table[ddp->command_id];
+	WARN_ON(q_entry->sgl_length == 0);
+
+	q_entry->ddp_ctx = ddp_ctx;
+	q_entry->queue = queue;
+
+	mlx5e_nvmeotcp_post_klm_wqe(queue, KLM_UMR, ddp->command_id, 0);
+
 	return 0;
 }
 
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.h
index d0e515502d6d..5a613addfc7c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.h
@@ -103,6 +103,7 @@ void mlx5e_nvmeotcp_cleanup(struct mlx5e_priv *priv);
 struct mlx5e_nvmeotcp_queue *
 mlx5e_nvmeotcp_get_queue(struct mlx5e_nvmeotcp *nvmeotcp, int id);
 void mlx5e_nvmeotcp_put_queue(struct mlx5e_nvmeotcp_queue *queue);
+void mlx5e_nvmeotcp_ddp_inv_done(struct mlx5e_icosq_wqe_info *wi);
 void mlx5e_nvmeotcp_ctx_comp(struct mlx5e_icosq_wqe_info *wi);
 int mlx5e_nvmeotcp_init_rx(struct mlx5e_priv *priv);
 void mlx5e_nvmeotcp_cleanup_rx(struct mlx5e_priv *priv);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
index 056fc24dd5ed..598d62366af2 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -630,6 +630,9 @@ void mlx5e_free_icosq_descs(struct mlx5e_icosq *sq)
 #ifdef CONFIG_MLX5_EN_NVMEOTCP
 		case MLX5E_ICOSQ_WQE_UMR_NVME_TCP:
 			break;
+		case MLX5E_ICOSQ_WQE_UMR_NVME_TCP_INVALIDATE:
+			mlx5e_nvmeotcp_ddp_inv_done(wi);
+			break;
 		case MLX5E_ICOSQ_WQE_SET_PSV_NVME_TCP:
 			mlx5e_nvmeotcp_ctx_comp(wi);
 			break;
@@ -707,6 +710,9 @@ int mlx5e_poll_ico_cq(struct mlx5e_cq *cq)
 #ifdef CONFIG_MLX5_EN_NVMEOTCP
 			case MLX5E_ICOSQ_WQE_UMR_NVME_TCP:
 				break;
+			case MLX5E_ICOSQ_WQE_UMR_NVME_TCP_INVALIDATE:
+				mlx5e_nvmeotcp_ddp_inv_done(wi);
+				break;
 			case MLX5E_ICOSQ_WQE_SET_PSV_NVME_TCP:
 				mlx5e_nvmeotcp_ctx_comp(wi);
 				break;
-- 
2.24.1



From borisp at mellanox.com  Thu Jan 14 10:10:27 2021
From: borisp at mellanox.com (Boris Pismenny)
Date: Thu, 14 Jan 2021 17:10:27 +0200
Subject: [PATCH v2 net-next 15/21] net/mlx5e: NVMEoTCP use KLM UMRs
In-Reply-To: <20210114151033.13020-1-borisp@mellanox.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
Message-ID: <20210114151033.13020-16-borisp@mellanox.com>

From: Ben Ben-Ishay <benishay at nvidia.com>

NVMEoTCP offload uses buffer registration for ddp operation,
every request comprises from SG list that might have elements with size > 4K,
thus the appropriate way to perform buffer registration is with KLM UMRs.

Signed-off-by: Boris Pismenny <borisp at mellanox.com>
Signed-off-by: Ben Ben-Ishay <benishay at nvidia.com>
Signed-off-by: Or Gerlitz <ogerlitz at mellanox.com>
Signed-off-by: Yoray Zack <yorayz at mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/en.h  |   5 +-
 .../net/ethernet/mellanox/mlx5/core/en/txrx.h |   3 +
 .../mellanox/mlx5/core/en_accel/nvmeotcp.c    | 116 ++++++++++++++++++
 .../mlx5/core/en_accel/nvmeotcp_utils.h       |  12 ++
 .../net/ethernet/mellanox/mlx5/core/en_rx.c   |  12 +-
 5 files changed, 145 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp_utils.h

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
index 26259d68b98a..dc6ebcfffb1b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@ -232,7 +232,10 @@ struct mlx5e_umr_wqe {
 	struct mlx5_wqe_ctrl_seg       ctrl;
 	struct mlx5_wqe_umr_ctrl_seg   uctrl;
 	struct mlx5_mkey_seg           mkc;
-	struct mlx5_mtt                inline_mtts[0];
+	union {
+		struct mlx5_mtt        inline_mtts[0];
+		struct mlx5_klm	       inline_klms[0];
+	};
 };
 
 extern const char mlx5e_self_tests[][ETH_GSTRING_LEN];
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h b/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
index 7943eb30b837..bfeea906612e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
@@ -34,6 +34,9 @@ enum mlx5e_icosq_wqe_type {
 	MLX5E_ICOSQ_WQE_SET_PSV_TLS,
 	MLX5E_ICOSQ_WQE_GET_PSV_TLS,
 #endif
+#ifdef CONFIG_MLX5_EN_NVMEOTCP
+	MLX5E_ICOSQ_WQE_UMR_NVME_TCP,
+#endif
 };
 
 /* General */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.c
index 0834deb7a3ac..bbeded08ef01 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.c
@@ -4,6 +4,7 @@
 #include <linux/netdevice.h>
 #include <linux/idr.h>
 #include "en_accel/nvmeotcp.h"
+#include "en_accel/nvmeotcp_utils.h"
 #include "en_accel/fs_tcp.h"
 #include "en/txrx.h"
 
@@ -19,6 +20,121 @@ static const struct rhashtable_params rhash_queues = {
 	.max_size = MAX_NVMEOTCP_QUEUES,
 };
 
+static void
+fill_nvmeotcp_klm_wqe(struct mlx5e_nvmeotcp_queue *queue,
+		      struct mlx5e_umr_wqe *wqe, u16 ccid, u32 klm_entries,
+		      u16 klm_offset)
+{
+	struct scatterlist *sgl_mkey;
+	u32 lkey, i;
+
+	lkey = queue->priv->mdev->mlx5e_res.mkey.key;
+	for (i = 0; i < klm_entries; i++) {
+		sgl_mkey = &queue->ccid_table[ccid].sgl[i + klm_offset];
+		wqe->inline_klms[i].bcount = cpu_to_be32(sgl_mkey->length);
+		wqe->inline_klms[i].key	   = cpu_to_be32(lkey);
+		wqe->inline_klms[i].va	   = cpu_to_be64(sgl_mkey->dma_address);
+	}
+
+	for (; i < ALIGN(klm_entries, KLM_ALIGNMENT); i++) {
+		wqe->inline_klms[i].bcount = 0;
+		wqe->inline_klms[i].key    = 0;
+		wqe->inline_klms[i].va     = 0;
+	}
+}
+
+static void
+build_nvmeotcp_klm_umr(struct mlx5e_nvmeotcp_queue *queue,
+		       struct mlx5e_umr_wqe *wqe, u16 ccid, int klm_entries,
+		       u32 klm_offset, u32 len)
+{
+	u32 id = queue->ccid_table[ccid].klm_mkey.key;
+	struct mlx5_wqe_umr_ctrl_seg *ucseg = &wqe->uctrl;
+	struct mlx5_wqe_ctrl_seg      *cseg = &wqe->ctrl;
+	struct mlx5_mkey_seg	       *mkc = &wqe->mkc;
+
+	u32 sqn = queue->sq->icosq.sqn;
+	u16 pc = queue->sq->icosq.pc;
+
+	cseg->opmod_idx_opcode = cpu_to_be32((pc << MLX5_WQE_CTRL_WQE_INDEX_SHIFT) |
+					     MLX5_OPCODE_UMR);
+	cseg->qpn_ds = cpu_to_be32((sqn << MLX5_WQE_CTRL_QPN_SHIFT) |
+				   MLX5E_KLM_UMR_DS_CNT(ALIGN(klm_entries, KLM_ALIGNMENT)));
+	cseg->general_id = cpu_to_be32(id);
+
+	if (!klm_offset) {
+		ucseg->mkey_mask |= cpu_to_be64(MLX5_MKEY_MASK_XLT_OCT_SIZE |
+						MLX5_MKEY_MASK_LEN | MLX5_MKEY_MASK_FREE);
+		mkc->xlt_oct_size = cpu_to_be32(ALIGN(len, KLM_ALIGNMENT));
+		mkc->len = cpu_to_be64(queue->ccid_table[ccid].size);
+	}
+
+	ucseg->flags = MLX5_UMR_INLINE | MLX5_UMR_TRANSLATION_OFFSET_EN;
+	ucseg->xlt_octowords = cpu_to_be16(ALIGN(klm_entries, KLM_ALIGNMENT));
+	ucseg->xlt_offset = cpu_to_be16(klm_offset);
+	fill_nvmeotcp_klm_wqe(queue, wqe, ccid, klm_entries, klm_offset);
+}
+
+static void
+mlx5e_nvmeotcp_fill_wi(struct mlx5e_nvmeotcp_queue *nvmeotcp_queue,
+		       struct mlx5e_icosq *sq, u32 wqe_bbs, u16 pi)
+{
+	struct mlx5e_icosq_wqe_info *wi = &sq->db.wqe_info[pi];
+
+	wi->num_wqebbs = wqe_bbs;
+	wi->wqe_type = MLX5E_ICOSQ_WQE_UMR_NVME_TCP;
+}
+
+static void
+post_klm_wqe(struct mlx5e_nvmeotcp_queue *queue,
+	     u16 ccid,
+	     u32 klm_length,
+	     u32 *klm_offset)
+{
+	struct mlx5e_icosq *sq = &queue->sq->icosq;
+	u32 wqe_bbs, cur_klm_entries;
+	struct mlx5e_umr_wqe *wqe;
+	u16 pi, wqe_sz;
+
+	cur_klm_entries = min_t(int, queue->max_klms_per_wqe,
+				klm_length - *klm_offset);
+	wqe_sz = MLX5E_KLM_UMR_WQE_SZ(ALIGN(cur_klm_entries, KLM_ALIGNMENT));
+	wqe_bbs = DIV_ROUND_UP(wqe_sz, MLX5_SEND_WQE_BB);
+	pi = mlx5e_icosq_get_next_pi(sq, wqe_bbs);
+	wqe = MLX5E_NVMEOTCP_FETCH_KLM_WQE(sq, pi);
+	mlx5e_nvmeotcp_fill_wi(queue, sq, wqe_bbs, pi);
+	build_nvmeotcp_klm_umr(queue, wqe, ccid, cur_klm_entries, *klm_offset,
+			       klm_length);
+	*klm_offset += cur_klm_entries;
+	sq->pc += wqe_bbs;
+	sq->doorbell_cseg = &wqe->ctrl;
+}
+
+static int
+mlx5e_nvmeotcp_post_klm_wqe(struct mlx5e_nvmeotcp_queue *queue,
+			    u16 ccid,
+			    u32 klm_length)
+{
+	u32 klm_offset = 0, wqes, wqe_sz, max_wqe_bbs, i, room;
+	struct mlx5e_icosq *sq = &queue->sq->icosq;
+
+	/* TODO: set stricter wqe_sz; using max for now */
+	wqes = DIV_ROUND_UP(klm_length, queue->max_klms_per_wqe);
+	wqe_sz = MLX5E_KLM_UMR_WQE_SZ(queue->max_klms_per_wqe);
+
+	max_wqe_bbs = DIV_ROUND_UP(wqe_sz, MLX5_SEND_WQE_BB);
+
+	room = mlx5e_stop_room_for_wqe(max_wqe_bbs) * wqes;
+	if (unlikely(!mlx5e_wqc_has_room_for(&sq->wq, sq->cc, sq->pc, room)))
+		return -ENOSPC;
+
+	for (i = 0; i < wqes; i++)
+		post_klm_wqe(queue, ccid, klm_length, &klm_offset);
+
+	mlx5e_notify_hw(&sq->wq, sq->pc, sq->uar_map, sq->doorbell_cseg);
+	return 0;
+}
+
 static int
 mlx5e_nvmeotcp_offload_limits(struct net_device *netdev,
 			      struct tcp_ddp_limits *limits)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp_utils.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp_utils.h
new file mode 100644
index 000000000000..329e114d6571
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp_utils.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2021 Mellanox Technologies. */
+#ifndef __MLX5E_NVMEOTCP_UTILS_H__
+#define __MLX5E_NVMEOTCP_UTILS_H__
+
+#include "en.h"
+
+#define MLX5E_NVMEOTCP_FETCH_KLM_WQE(sq, pi) \
+	((struct mlx5e_umr_wqe *)\
+	 mlx5e_fetch_wqe(&(sq)->wq, pi, sizeof(struct mlx5e_umr_wqe)))
+
+#endif /* __MLX5E_NVMEOTCP_UTILS_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
index 377e547840f3..28aa99265c0a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -617,16 +617,20 @@ void mlx5e_free_icosq_descs(struct mlx5e_icosq *sq)
 		ci = mlx5_wq_cyc_ctr2ix(&sq->wq, sqcc);
 		wi = &sq->db.wqe_info[ci];
 		sqcc += wi->num_wqebbs;
-#ifdef CONFIG_MLX5_EN_TLS
 		switch (wi->wqe_type) {
+#ifdef CONFIG_MLX5_EN_TLS
 		case MLX5E_ICOSQ_WQE_SET_PSV_TLS:
 			mlx5e_ktls_handle_ctx_completion(wi);
 			break;
 		case MLX5E_ICOSQ_WQE_GET_PSV_TLS:
 			mlx5e_ktls_handle_get_psv_completion(wi, sq);
 			break;
-		}
 #endif
+#ifdef CONFIG_MLX5_EN_NVMEOTCP
+		case MLX5E_ICOSQ_WQE_UMR_NVME_TCP:
+			break;
+#endif
+		}
 	}
 	sq->cc = sqcc;
 }
@@ -695,6 +699,10 @@ int mlx5e_poll_ico_cq(struct mlx5e_cq *cq)
 			case MLX5E_ICOSQ_WQE_GET_PSV_TLS:
 				mlx5e_ktls_handle_get_psv_completion(wi, sq);
 				break;
+#endif
+#ifdef CONFIG_MLX5_EN_NVMEOTCP
+			case MLX5E_ICOSQ_WQE_UMR_NVME_TCP:
+				break;
 #endif
 			default:
 				netdev_WARN_ONCE(cq->netdev,
-- 
2.24.1



From borisp at mellanox.com  Thu Jan 14 10:10:12 2021
From: borisp at mellanox.com (Boris Pismenny)
Date: Thu, 14 Jan 2021 17:10:12 +0200
Subject: [PATCH v2 net-next 00/21] nvme-tcp receive offloads
Message-ID: <20210114151033.13020-1-borisp@mellanox.com>

Changes since v1:
=========================================
* Rework iov_iter copy skip if src==dst to be less intrusive (David Ahern)
* Add tcp-ddp documentation (David Ahern)
* Refactor mellanox driver patches into more patches (Saeed Mahameed)
* Avoid pointer casting (David Ahern)
* Rename nvme-tcp offload flags (Shai Malin)
* Update cover-letter according to the above

Changes since RFC v1:
=========================================
* Split mlx5 driver patches to several commits
* Fix nvme-tcp handling of recovery flows. In particular, move queue offlaod
  init/teardown to the start/stop functions.

Overview
=========================================
This series adds support for nvme-tcp receive offloads
which do not mandate the offload of the network stack to the device.
Instead, these work together with TCP to offload:
1. copy from SKB to the block layer buffers
2. CRC verification for received PDU

The series implements these as a generic offload infrastructure for storage
protocols, which we call TCP Direct Data Placement (TCP_DDP) and TCP DDP CRC,
respectively. We use this infrastructure to implement NVMe-TCP offload for copy
and CRC. Future implementations can reuse the same infrastructure for other
protcols such as iSCSI.

Note:
These offloads are similar in nature to the packet-based NIC TLS offloads,
which are already upstream (see net/tls/tls_device.c).
You can read more about TLS offload here:
https://www.kernel.org/doc/html/latest/networking/tls-offload.html

Initialization and teardown:
=========================================
The offload for IO queues is initialized after the handshake of the
NVMe-TCP protocol is finished by calling `nvme_tcp_offload_socket`
with the tcp socket of the nvme_tcp_queue:
This operation sets all relevant hardware contexts in
hardware. If it fails, then the IO queue proceeds as usually with no offload.
If it succeeds then `nvme_tcp_setup_ddp` and `nvme_tcp_teardown_ddp` may be
called to perform copy offload, and crc offload will be used.
This initialization does not change the normal operation of nvme-tcp in any
way besides adding the option to call the above mentioned NDO operations.

For the admin queue, nvme-tcp does not initialize the offload.
Instead, nvme-tcp calls the driver to configure limits for the controller,
such as max_hw_sectors and max_segments; these must be limited to accomodate
potential HW resource limits, and to improve performance.

If some error occured, and the IO queue must be closed or reconnected, then
offload is teardown and initialized again. Additionally, we handle netdev
down events via the existing error recovery flow.

Copy offload works as follows:
=========================================
The nvme-tcp layer calls the NIC drive to map block layer buffers to ccid using
`nvme_tcp_setup_ddp` before sending the read request. When the repsonse is
received, then the NIC HW will write the PDU payload directly into the
designated buffer, and build an SKB such that it points into the destination
buffer; this SKB represents the entire packet received on the wire, but it
points to the block layer buffers. Once nvme-tcp attempts to copy data from
this SKB to the block layer buffer it can skip the copy by checking in the
copying function (memcpy_to_page):
if (src == dst) -> skip copy
Finally, when the PDU has been processed to completion, the nvme-tcp layer
releases the NIC HW context be calling `nvme_tcp_teardown_ddp` which
asynchronously unmaps the buffers from NIC HW.

As the copy skip change is in a sensative function, we are careful to avoid
changing it. To that end, we create alternative skb copy and hash iterators
that skip copy/hash if (src == dst). Nvme-tcp is the first user for these.

Asynchronous completion:
=========================================
The NIC must release its mapping between command IDs and the target buffers.
This mapping is released when NVMe-TCP calls the NIC
driver (`nvme_tcp_offload_socket`).
As completing IOs is performance criticial, we introduce asynchronous
completions for NVMe-TCP, i.e. NVMe-TCP calls the NIC, which will later
call NVMe-TCP to complete the IO (`nvme_tcp_ddp_teardown_done`).

An alternative approach is to move all the functions related to coping from
SKBs to the block layer buffers inside the nvme-tcp code - about 200 LOC.

CRC offload works as follows:
=========================================
After offload is initialized, we use the SKB's ddp_crc bit to indicate that:
"there was no problem with the verification of all CRC fields in this packet's
payload". The bit is set to zero if there was an error, or if HW skipped
offload for some reason. If *any* SKB in a PDU has (ddp_crc != 1), then software
must compute the CRC, and check it. We perform this check, and
accompanying software fallback at the end of the processing of a received PDU.

SKB changes:
=========================================
The CRC offload requires an additional bit in the SKB, which is useful for
preventing the coalescing of SKB with different crc offload values. This bit
is similar in concept to the "decrypted" bit. 

Performance:
=========================================
The expected performance gain from this offload varies with the block size.
We perform a CPU cycles breakdown of the copy/CRC operations in nvme-tcp
fio random read workloads:
For 4K blocks we see up to 11% improvement for a 100% read fio workload,
while for 128K blocks we see upto 52%. If we run nvme-tcp, and skip these
operations, then we observe a gain of about 1.1x and 2x respectively.

Resynchronization:
=========================================
The resynchronization flow is performed to reset the hardware tracking of
NVMe-TCP PDUs within the TCP stream. The flow consists of a request from
the driver, regarding a possible location of a PDU header. Followed by
a response from the nvme-tcp driver.

This flow is rare, and it should happen only after packet loss or
reordering events that involve nvme-tcp PDU headers.

The patches are organized as follows:
=========================================
Patch 1         the iov_iter change to skip copy if (src == dst).
Patches 2-4     the infrastructure for all TCP DDP.
                and TCP DDP CRC offloads, respectively.
Patch 5         exposes the get_netdev_for_sock function from TLS.
Patch 6         NVMe-TCP changes to call NIC driver on queue init/teardown.
Patches 7       NVMe-TCP changes to call NIC driver on IO operation.
                setup/teardown, and support async completions.
Patches 8       NVMe-TCP changes to support CRC offload on receive.
                Also, this patch moves CRC calculation to the end of PDU
                in case offload requires software fallback.
Patches 9       NVMe-TCP handling of netdev events: stop the offload if
                netdev is going down.
Patches 10-20   implement support for NVMe-TCP copy and CRC offload in
                the mlx5 NIC driver as the first user.
Patches 21      Document TCP DDP offload.

Testing:
=========================================
This series was tested using fio with various configurations of IO sizes,
depths, MTUs, and with both the SPDK and kernel NVMe-TCP targets.
Also, we have used QEMU and gate-level simulation to verify these patches.

Future work:
=========================================
A follow-up series will introduce support for transmit side CRC. Then,
we will work on adding support for TLS in NVMe-TCP and combining the
two offloads.

Ben Ben-Ishay (8):
  net/mlx5e: NVMEoTCP offload initialization
  net/mlx5e: KLM UMR helper macros
  net/mlx5e: NVMEoTCP use KLM UMRs
  net/mlx5e: NVMEoTCP queue init/teardown
  net/mlx5e: NVMEoTCP async ddp invalidation
  net/mlx5e: NVMEoTCP ddp setup and resync
  net/mlx5e: NVMEoTCP, data-path for DDP offload
  net/mlx5e: NVMEoTCP statistics

Ben Ben-ishay (4):
  net: SKB copy(+hash) iterators for DDP offloads
  nvme-tcp : Recalculate crc in the end of the capsule
  net/mlx5: Header file changes for nvme-tcp offload
  net/mlx5: Add 128B CQE for NVMEoTCP offload

Boris Pismenny (8):
  iov_iter: Introduce new procedures for copy to iter/pages
  net: Introduce direct data placement tcp offload
  net: Introduce crc offload for tcp ddp ulp
  net/tls: expose get_netdev_for_sock
  nvme-tcp: Add DDP offload control path
  nvme-tcp: Add DDP data-path
  net/mlx5e: TCP flow steering for nvme-tcp
  Documentation: add TCP DDP offload documentation

Or Gerlitz (1):
  nvme-tcp: Deal with netdevice DOWN events

 Documentation/networking/index.rst            |    1 +
 Documentation/networking/tcp-ddp-offload.rst  |  296 +++++
 .../net/ethernet/mellanox/mlx5/core/Kconfig   |   11 +
 .../net/ethernet/mellanox/mlx5/core/Makefile  |    2 +
 drivers/net/ethernet/mellanox/mlx5/core/en.h  |   31 +-
 .../net/ethernet/mellanox/mlx5/core/en/fs.h   |    4 +-
 .../ethernet/mellanox/mlx5/core/en/params.h   |    1 +
 .../net/ethernet/mellanox/mlx5/core/en/txrx.h |   13 +
 .../ethernet/mellanox/mlx5/core/en/xsk/rx.c   |    1 +
 .../ethernet/mellanox/mlx5/core/en/xsk/rx.h   |    1 +
 .../mellanox/mlx5/core/en_accel/en_accel.h    |    9 +-
 .../mellanox/mlx5/core/en_accel/fs_tcp.c      |   10 +
 .../mellanox/mlx5/core/en_accel/fs_tcp.h      |    2 +-
 .../mellanox/mlx5/core/en_accel/nvmeotcp.c    | 1012 +++++++++++++++++
 .../mellanox/mlx5/core/en_accel/nvmeotcp.h    |  120 ++
 .../mlx5/core/en_accel/nvmeotcp_rxtx.c        |  259 +++++
 .../mlx5/core/en_accel/nvmeotcp_rxtx.h        |   43 +
 .../mlx5/core/en_accel/nvmeotcp_utils.h       |   80 ++
 .../net/ethernet/mellanox/mlx5/core/en_main.c |   39 +-
 .../net/ethernet/mellanox/mlx5/core/en_rx.c   |   66 +-
 .../ethernet/mellanox/mlx5/core/en_stats.c    |   37 +
 .../ethernet/mellanox/mlx5/core/en_stats.h    |   24 +
 .../net/ethernet/mellanox/mlx5/core/en_txrx.c |   17 +
 drivers/net/ethernet/mellanox/mlx5/core/fw.c  |    6 +
 drivers/nvme/host/tcp.c                       |  466 +++++++-
 include/linux/mlx5/device.h                   |   44 +-
 include/linux/mlx5/mlx5_ifc.h                 |  101 +-
 include/linux/mlx5/qp.h                       |    1 +
 include/linux/netdev_features.h               |    4 +
 include/linux/netdevice.h                     |    5 +
 include/linux/skbuff.h                        |   10 +
 include/linux/uio.h                           |   12 +
 include/net/inet_connection_sock.h            |    4 +
 include/net/sock.h                            |   17 +
 include/net/tcp_ddp.h                         |  136 +++
 lib/iov_iter.c                                |   45 +
 net/Kconfig                                   |   17 +
 net/core/datagram.c                           |   44 +
 net/core/skbuff.c                             |    9 +-
 net/ethtool/common.c                          |    2 +
 net/ipv4/tcp_input.c                          |    7 +
 net/ipv4/tcp_ipv4.c                           |    3 +
 net/ipv4/tcp_offload.c                        |    3 +
 net/tls/tls_device.c                          |   20 +-
 44 files changed, 2977 insertions(+), 58 deletions(-)
 create mode 100644 Documentation/networking/tcp-ddp-offload.rst
 create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.c
 create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.h
 create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp_rxtx.c
 create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp_rxtx.h
 create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp_utils.h
 create mode 100644 include/net/tcp_ddp.h

-- 
2.24.1



From borisp at mellanox.com  Thu Jan 14 10:10:17 2021
From: borisp at mellanox.com (Boris Pismenny)
Date: Thu, 14 Jan 2021 17:10:17 +0200
Subject: [PATCH v2 net-next 05/21] net/tls: expose get_netdev_for_sock
In-Reply-To: <20210114151033.13020-1-borisp@mellanox.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
Message-ID: <20210114151033.13020-6-borisp@mellanox.com>

get_netdev_for_sock is a utility that is used to obtain
the net_device structure from a connected socket.

Later patches will use this for nvme-tcp DDP and DDP CRC offloads.

Signed-off-by: Boris Pismenny <borisp at mellanox.com>
Reviewed-by: Sagi Grimberg <sagi at grimberg.me>
---
 include/net/sock.h   | 17 +++++++++++++++++
 net/tls/tls_device.c | 20 ++------------------
 2 files changed, 19 insertions(+), 18 deletions(-)

diff --git a/include/net/sock.h b/include/net/sock.h
index bdc4323ce53c..9c21a4d696ad 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -2721,4 +2721,21 @@ void sock_set_sndtimeo(struct sock *sk, s64 secs);
 
 int sock_bind_add(struct sock *sk, struct sockaddr *addr, int addr_len);
 
+/* Assume that the socket is already connected */
+static inline struct net_device *get_netdev_for_sock(struct sock *sk, bool hold)
+{
+	struct dst_entry *dst = sk_dst_get(sk);
+	struct net_device *netdev = NULL;
+
+	if (likely(dst)) {
+		netdev = dst->dev;
+		if (hold)
+			dev_hold(netdev);
+	}
+
+	dst_release(dst);
+
+	return netdev;
+}
+
 #endif	/* _SOCK_H */
diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c
index f7fb7d2c1de1..cbd24d897023 100644
--- a/net/tls/tls_device.c
+++ b/net/tls/tls_device.c
@@ -106,22 +106,6 @@ static void tls_device_queue_ctx_destruction(struct tls_context *ctx)
 	spin_unlock_irqrestore(&tls_device_lock, flags);
 }
 
-/* We assume that the socket is already connected */
-static struct net_device *get_netdev_for_sock(struct sock *sk)
-{
-	struct dst_entry *dst = sk_dst_get(sk);
-	struct net_device *netdev = NULL;
-
-	if (likely(dst)) {
-		netdev = dst->dev;
-		dev_hold(netdev);
-	}
-
-	dst_release(dst);
-
-	return netdev;
-}
-
 static void destroy_record(struct tls_record_info *record)
 {
 	int i;
@@ -1106,7 +1090,7 @@ int tls_set_device_offload(struct sock *sk, struct tls_context *ctx)
 	if (skb)
 		TCP_SKB_CB(skb)->eor = 1;
 
-	netdev = get_netdev_for_sock(sk);
+	netdev = get_netdev_for_sock(sk, true);
 	if (!netdev) {
 		pr_err_ratelimited("%s: netdev not found\n", __func__);
 		rc = -EINVAL;
@@ -1182,7 +1166,7 @@ int tls_set_device_offload_rx(struct sock *sk, struct tls_context *ctx)
 	if (ctx->crypto_recv.info.version != TLS_1_2_VERSION)
 		return -EOPNOTSUPP;
 
-	netdev = get_netdev_for_sock(sk);
+	netdev = get_netdev_for_sock(sk, true);
 	if (!netdev) {
 		pr_err_ratelimited("%s: netdev not found\n", __func__);
 		return -EINVAL;
-- 
2.24.1



From borisp at mellanox.com  Thu Jan 14 10:10:23 2021
From: borisp at mellanox.com (Boris Pismenny)
Date: Thu, 14 Jan 2021 17:10:23 +0200
Subject: [PATCH v2 net-next 11/21] net/mlx5: Add 128B CQE for NVMEoTCP offload
In-Reply-To: <20210114151033.13020-1-borisp@mellanox.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
Message-ID: <20210114151033.13020-12-borisp@mellanox.com>

From: Ben Ben-ishay <benishay at nvidia.com>

Add the NVMEoTCP offload definition and access functions for 128B CQEs.

Signed-off-by: Ben Ben-ishay <benishay at nvidia.com>
Signed-off-by: Boris Pismenny <borisp at mellanox.com>
Signed-off-by: Or Gerlitz <ogerlitz at mellanox.com>
Signed-off-by: Yoray Zack <yorayz at mellanox.com>
---
 include/linux/mlx5/device.h | 36 +++++++++++++++++++++++++++++++++++-
 1 file changed, 35 insertions(+), 1 deletion(-)

diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h
index 4433ff213d32..f4912d6c42f8 100644
--- a/include/linux/mlx5/device.h
+++ b/include/linux/mlx5/device.h
@@ -791,7 +791,7 @@ struct mlx5_err_cqe {
 
 struct mlx5_cqe64 {
 	u8		tls_outer_l3_tunneled;
-	u8		rsvd0;
+	u8		nvmetcp;
 	__be16		wqe_id;
 	u8		lro_tcppsh_abort_dupack;
 	u8		lro_min_ttl;
@@ -824,6 +824,19 @@ struct mlx5_cqe64 {
 	u8		op_own;
 };
 
+struct mlx5e_cqe128 {
+	__be16		cclen;
+	__be16		hlen;
+	union {
+		__be32		resync_tcp_sn;
+		__be32		ccoff;
+	};
+	__be16		ccid;
+	__be16		rsvd8;
+	u8		rsvd12[52];
+	struct mlx5_cqe64 cqe64;
+};
+
 struct mlx5_mini_cqe8 {
 	union {
 		__be32 rx_hash_result;
@@ -854,6 +867,27 @@ enum {
 
 #define MLX5_MINI_CQE_ARRAY_SIZE 8
 
+static inline bool cqe_is_nvmeotcp_resync(struct mlx5_cqe64 *cqe)
+{
+	return ((cqe->nvmetcp >> 6) & 0x1);
+}
+
+static inline bool cqe_is_nvmeotcp_crcvalid(struct mlx5_cqe64 *cqe)
+{
+	return ((cqe->nvmetcp >> 5) & 0x1);
+}
+
+static inline bool cqe_is_nvmeotcp_zc(struct mlx5_cqe64 *cqe)
+{
+	return ((cqe->nvmetcp >> 4) & 0x1);
+}
+
+/* check if cqe is zc or crc or resync */
+static inline bool cqe_is_nvmeotcp(struct mlx5_cqe64 *cqe)
+{
+	return ((cqe->nvmetcp >> 4) & 0x7);
+}
+
 static inline u8 mlx5_get_cqe_format(struct mlx5_cqe64 *cqe)
 {
 	return (cqe->op_own >> 2) & 0x3;
-- 
2.24.1



From borisp at mellanox.com  Thu Jan 14 10:10:28 2021
From: borisp at mellanox.com (Boris Pismenny)
Date: Thu, 14 Jan 2021 17:10:28 +0200
Subject: [PATCH v2 net-next 16/21] net/mlx5e: NVMEoTCP queue init/teardown
In-Reply-To: <20210114151033.13020-1-borisp@mellanox.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
Message-ID: <20210114151033.13020-17-borisp@mellanox.com>

From: Ben Ben-Ishay <benishay at nvidia.com>

When nvme-tcp establishes new connections, we allocate a hardware
context to offload operations for this queue:
- Use a separate TIR to identify the queue and maintain the HW context
- Use a separate ICOSQ for maintain the HW context
- Use a separate tag buffer for buffer registration
- Maintain static and progress HW contexts by posting the proper
  WQEs at creation time, or upon resync

Queue teardown will free the corresponding contexts.

Signed-off-by: Boris Pismenny <borisp at mellanox.com>
Signed-off-by: Ben Ben-Ishay <benishay at nvidia.com>
Signed-off-by: Or Gerlitz <ogerlitz at mellanox.com>
Signed-off-by: Yoray Zack <yorayz at mellanox.com>
---
 .../net/ethernet/mellanox/mlx5/core/en/txrx.h |   6 +
 .../mellanox/mlx5/core/en_accel/nvmeotcp.c    | 650 +++++++++++++++++-
 .../mellanox/mlx5/core/en_accel/nvmeotcp.h    |   4 +
 .../mlx5/core/en_accel/nvmeotcp_utils.h       |  68 ++
 .../net/ethernet/mellanox/mlx5/core/en_rx.c   |   7 +
 5 files changed, 711 insertions(+), 24 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h b/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
index bfeea906612e..f00d76f1ded4 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
@@ -36,6 +36,7 @@ enum mlx5e_icosq_wqe_type {
 #endif
 #ifdef CONFIG_MLX5_EN_NVMEOTCP
 	MLX5E_ICOSQ_WQE_UMR_NVME_TCP,
+	MLX5E_ICOSQ_WQE_SET_PSV_NVME_TCP,
 #endif
 };
 
@@ -178,6 +179,11 @@ struct mlx5e_icosq_wqe_info {
 		struct {
 			struct mlx5e_ktls_rx_resync_buf *buf;
 		} tls_get_params;
+#endif
+#ifdef CONFIG_MLX5_EN_NVMEOTCP
+		struct {
+			struct mlx5e_nvmeotcp_queue *queue;
+		} nvmeotcp_q;
 #endif
 	};
 };
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.c
index bbeded08ef01..3a42477f1bd7 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.c
@@ -3,6 +3,7 @@
 
 #include <linux/netdevice.h>
 #include <linux/idr.h>
+#include <linux/nvme-tcp.h>
 #include "en_accel/nvmeotcp.h"
 #include "en_accel/nvmeotcp_utils.h"
 #include "en_accel/fs_tcp.h"
@@ -20,35 +21,180 @@ static const struct rhashtable_params rhash_queues = {
 	.max_size = MAX_NVMEOTCP_QUEUES,
 };
 
+#define MLX5_NVME_TCP_MAX_SEGMENTS 128
+
+static u32 mlx5e_get_max_sgl(struct mlx5_core_dev *mdev)
+{
+	return min_t(u32,
+		     MLX5_NVME_TCP_MAX_SEGMENTS,
+		     1 << MLX5_CAP_GEN(mdev, log_max_klm_list_size));
+}
+
+static void mlx5e_nvmeotcp_destroy_tir(struct mlx5e_priv *priv, int tirn)
+{
+	mlx5_core_destroy_tir(priv->mdev, tirn);
+}
+
+static inline u32
+mlx5e_get_channel_ix_from_io_cpu(struct mlx5e_priv *priv, u32 io_cpu)
+{
+	int num_channels = priv->channels.params.num_channels;
+	u32 channel_ix = io_cpu;
+
+	if (channel_ix >= num_channels)
+		channel_ix = channel_ix % num_channels;
+
+	return channel_ix;
+}
+
+static int mlx5e_nvmeotcp_create_tir(struct mlx5e_priv *priv,
+				     struct sock *sk,
+				     struct nvme_tcp_ddp_config *config,
+				     struct mlx5e_nvmeotcp_queue *queue,
+				     bool zerocopy, bool crc_rx)
+{
+	u32 rqtn = priv->direct_tir[queue->channel_ix].rqt.rqtn;
+	int err, inlen;
+	void *tirc;
+	u32 tirn;
+	u32 *in;
+
+	inlen = MLX5_ST_SZ_BYTES(create_tir_in);
+	in = kvzalloc(inlen, GFP_KERNEL);
+	if (!in)
+		return -ENOMEM;
+	tirc = MLX5_ADDR_OF(create_tir_in, in, ctx);
+	MLX5_SET(tirc, tirc, disp_type, MLX5_TIRC_DISP_TYPE_INDIRECT);
+	MLX5_SET(tirc, tirc, rx_hash_fn, MLX5_RX_HASH_FN_INVERTED_XOR8);
+	MLX5_SET(tirc, tirc, indirect_table, rqtn);
+	MLX5_SET(tirc, tirc, transport_domain, priv->mdev->mlx5e_res.td.tdn);
+	if (zerocopy) {
+		MLX5_SET(tirc, tirc, nvmeotcp_zero_copy_en, 1);
+		MLX5_SET(tirc, tirc, nvmeotcp_tag_buffer_table_id,
+			 queue->tag_buf_table_id);
+	}
+
+	if (crc_rx)
+		MLX5_SET(tirc, tirc, nvmeotcp_crc_en, 1);
+
+	MLX5_SET(tirc, tirc, self_lb_block,
+		 MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST |
+		 MLX5_TIRC_SELF_LB_BLOCK_BLOCK_MULTICAST);
+	err = mlx5_core_create_tir(priv->mdev, in, &tirn);
+
+	if (!err)
+		queue->tirn = tirn;
+
+	kvfree(in);
+	return err;
+}
+
+static
+int mlx5e_create_nvmeotcp_tag_buf_table(struct mlx5_core_dev *mdev,
+					struct mlx5e_nvmeotcp_queue *queue,
+					u8 log_table_size)
+{
+	u32 in[MLX5_ST_SZ_DW(create_nvmeotcp_tag_buf_table_in)] = {};
+	u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)];
+	u64 general_obj_types;
+	void *obj;
+	int err;
+
+	obj = MLX5_ADDR_OF(create_nvmeotcp_tag_buf_table_in, in,
+			   nvmeotcp_tag_buf_table_obj);
+
+	general_obj_types = MLX5_CAP_GEN_64(mdev, general_obj_types);
+	if (!(general_obj_types &
+	      MLX5_HCA_CAP_GENERAL_OBJECT_TYPES_NVMEOTCP_TAG_BUFFER_TABLE))
+		return -EINVAL;
+
+	MLX5_SET(general_obj_in_cmd_hdr, in, opcode,
+		 MLX5_CMD_OP_CREATE_GENERAL_OBJECT);
+	MLX5_SET(general_obj_in_cmd_hdr, in, obj_type,
+		 MLX5_GENERAL_OBJECT_TYPES_NVMEOTCP_TAG_BUFFER_TABLE);
+	MLX5_SET(nvmeotcp_tag_buf_table_obj, obj,
+		 log_tag_buffer_table_size, log_table_size);
+
+	err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
+	if (!err)
+		queue->tag_buf_table_id = MLX5_GET(general_obj_out_cmd_hdr,
+						   out, obj_id);
+	return err;
+}
+
+static
+void mlx5_destroy_nvmeotcp_tag_buf_table(struct mlx5_core_dev *mdev, u32 uid)
+{
+	u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {};
+	u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)];
+
+	MLX5_SET(general_obj_in_cmd_hdr, in, opcode,
+		 MLX5_CMD_OP_DESTROY_GENERAL_OBJECT);
+	MLX5_SET(general_obj_in_cmd_hdr, in, obj_type,
+		 MLX5_GENERAL_OBJECT_TYPES_NVMEOTCP_TAG_BUFFER_TABLE);
+	MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, uid);
+
+	mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
+}
+
+#define MLX5_CTRL_SEGMENT_OPC_MOD_UMR_TIR_PARAMS 0x2
+#define MLX5_CTRL_SEGMENT_OPC_MOD_UMR_NVMEOTCP_TIR_STATIC_PARAMS 0x2
+#define MLX5_CTRL_SEGMENT_OPC_MOD_UMR_UMR 0x0
+
+#define STATIC_PARAMS_DS_CNT \
+	DIV_ROUND_UP(MLX5E_NVMEOTCP_STATIC_PARAMS_WQE_SZ, MLX5_SEND_WQE_DS)
+
+#define PROGRESS_PARAMS_DS_CNT \
+	DIV_ROUND_UP(MLX5E_NVMEOTCP_PROGRESS_PARAMS_WQE_SZ, MLX5_SEND_WQE_DS)
+
+enum wqe_type {
+	KLM_UMR = 0,
+	BSF_KLM_UMR = 1,
+	SET_PSV_UMR = 2,
+	BSF_UMR = 3,
+};
+
 static void
 fill_nvmeotcp_klm_wqe(struct mlx5e_nvmeotcp_queue *queue,
 		      struct mlx5e_umr_wqe *wqe, u16 ccid, u32 klm_entries,
-		      u16 klm_offset)
+		      u16 klm_offset, enum wqe_type klm_type)
 {
 	struct scatterlist *sgl_mkey;
 	u32 lkey, i;
 
-	lkey = queue->priv->mdev->mlx5e_res.mkey.key;
-	for (i = 0; i < klm_entries; i++) {
-		sgl_mkey = &queue->ccid_table[ccid].sgl[i + klm_offset];
-		wqe->inline_klms[i].bcount = cpu_to_be32(sgl_mkey->length);
-		wqe->inline_klms[i].key	   = cpu_to_be32(lkey);
-		wqe->inline_klms[i].va	   = cpu_to_be64(sgl_mkey->dma_address);
-	}
-
-	for (; i < ALIGN(klm_entries, KLM_ALIGNMENT); i++) {
-		wqe->inline_klms[i].bcount = 0;
-		wqe->inline_klms[i].key    = 0;
-		wqe->inline_klms[i].va     = 0;
+	if (klm_type == BSF_KLM_UMR) {
+		for (i = 0; i < klm_entries; i++) {
+			lkey = queue->ccid_table[i + klm_offset].klm_mkey.key;
+			wqe->inline_klms[i].bcount = cpu_to_be32(1);
+			wqe->inline_klms[i].key	   = cpu_to_be32(lkey);
+			wqe->inline_klms[i].va	   = 0;
+		}
+	} else {
+		lkey = queue->priv->mdev->mlx5e_res.mkey.key;
+		for (i = 0; i < klm_entries; i++) {
+			sgl_mkey = &queue->ccid_table[ccid].sgl[i + klm_offset];
+			wqe->inline_klms[i].bcount = cpu_to_be32(sgl_mkey->length);
+			wqe->inline_klms[i].key	   = cpu_to_be32(lkey);
+			wqe->inline_klms[i].va	   = cpu_to_be64(sgl_mkey->dma_address);
+		}
+
+		for (; i < ALIGN(klm_entries, KLM_ALIGNMENT); i++) {
+			wqe->inline_klms[i].bcount = 0;
+			wqe->inline_klms[i].key    = 0;
+			wqe->inline_klms[i].va     = 0;
+		}
 	}
 }
 
 static void
 build_nvmeotcp_klm_umr(struct mlx5e_nvmeotcp_queue *queue,
 		       struct mlx5e_umr_wqe *wqe, u16 ccid, int klm_entries,
-		       u32 klm_offset, u32 len)
+		       u32 klm_offset, u32 len, enum wqe_type klm_type)
 {
-	u32 id = queue->ccid_table[ccid].klm_mkey.key;
+	u32 id = (klm_type == KLM_UMR) ? queue->ccid_table[ccid].klm_mkey.key :
+		(queue->tirn << MLX5_WQE_CTRL_TIR_TIS_INDEX_SHIFT);
+	u8 opc_mod = (klm_type == KLM_UMR) ? MLX5_CTRL_SEGMENT_OPC_MOD_UMR_UMR :
+		MLX5_CTRL_SEGMENT_OPC_MOD_UMR_NVMEOTCP_TIR_STATIC_PARAMS;
 	struct mlx5_wqe_umr_ctrl_seg *ucseg = &wqe->uctrl;
 	struct mlx5_wqe_ctrl_seg      *cseg = &wqe->ctrl;
 	struct mlx5_mkey_seg	       *mkc = &wqe->mkc;
@@ -57,12 +203,12 @@ build_nvmeotcp_klm_umr(struct mlx5e_nvmeotcp_queue *queue,
 	u16 pc = queue->sq->icosq.pc;
 
 	cseg->opmod_idx_opcode = cpu_to_be32((pc << MLX5_WQE_CTRL_WQE_INDEX_SHIFT) |
-					     MLX5_OPCODE_UMR);
+					     MLX5_OPCODE_UMR | (opc_mod) << 24);
 	cseg->qpn_ds = cpu_to_be32((sqn << MLX5_WQE_CTRL_QPN_SHIFT) |
 				   MLX5E_KLM_UMR_DS_CNT(ALIGN(klm_entries, KLM_ALIGNMENT)));
 	cseg->general_id = cpu_to_be32(id);
 
-	if (!klm_offset) {
+	if (klm_type == KLM_UMR && !klm_offset) {
 		ucseg->mkey_mask |= cpu_to_be64(MLX5_MKEY_MASK_XLT_OCT_SIZE |
 						MLX5_MKEY_MASK_LEN | MLX5_MKEY_MASK_FREE);
 		mkc->xlt_oct_size = cpu_to_be32(ALIGN(len, KLM_ALIGNMENT));
@@ -72,21 +218,150 @@ build_nvmeotcp_klm_umr(struct mlx5e_nvmeotcp_queue *queue,
 	ucseg->flags = MLX5_UMR_INLINE | MLX5_UMR_TRANSLATION_OFFSET_EN;
 	ucseg->xlt_octowords = cpu_to_be16(ALIGN(klm_entries, KLM_ALIGNMENT));
 	ucseg->xlt_offset = cpu_to_be16(klm_offset);
-	fill_nvmeotcp_klm_wqe(queue, wqe, ccid, klm_entries, klm_offset);
+	fill_nvmeotcp_klm_wqe(queue, wqe, ccid, klm_entries, klm_offset, klm_type);
+}
+
+static void
+fill_nvmeotcp_progress_params(struct mlx5e_nvmeotcp_queue *queue,
+			      struct mlx5_seg_nvmeotcp_progress_params *params,
+			      u32 seq)
+{
+	void *ctx = params->ctx;
+
+	params->tir_num = cpu_to_be32(queue->tirn);
+
+	MLX5_SET(nvmeotcp_progress_params, ctx,
+		 next_pdu_tcp_sn, seq);
+	MLX5_SET(nvmeotcp_progress_params, ctx, pdu_tracker_state,
+		 MLX5E_NVMEOTCP_PROGRESS_PARAMS_PDU_TRACKER_STATE_START);
+}
+
+void
+build_nvmeotcp_progress_params(struct mlx5e_nvmeotcp_queue *queue,
+			       struct mlx5e_set_nvmeotcp_progress_params_wqe *wqe,
+			       u32 seq)
+{
+	struct mlx5_wqe_ctrl_seg *cseg = &wqe->ctrl;
+	u32 sqn = queue->sq->icosq.sqn;
+	u16 pc = queue->sq->icosq.pc;
+	u8 opc_mod;
+
+	memset(wqe, 0, MLX5E_NVMEOTCP_PROGRESS_PARAMS_WQE_SZ);
+	opc_mod = MLX5_CTRL_SEGMENT_OPC_MOD_UMR_NVMEOTCP_TIR_PROGRESS_PARAMS;
+	cseg->opmod_idx_opcode = cpu_to_be32((pc << MLX5_WQE_CTRL_WQE_INDEX_SHIFT) |
+					     MLX5_OPCODE_SET_PSV | (opc_mod << 24));
+	cseg->qpn_ds = cpu_to_be32((sqn << MLX5_WQE_CTRL_QPN_SHIFT) |
+				   PROGRESS_PARAMS_DS_CNT);
+	fill_nvmeotcp_progress_params(queue, &wqe->params, seq);
+}
+
+static void
+fill_nvmeotcp_static_params(struct mlx5e_nvmeotcp_queue *queue,
+			    struct mlx5_seg_nvmeotcp_static_params *params,
+			    u32 resync_seq, bool zero_copy_en,
+			    bool ddgst_offload_en)
+{
+	void *ctx = params->ctx;
+
+	MLX5_SET(transport_static_params, ctx, const_1, 1);
+	MLX5_SET(transport_static_params, ctx, const_2, 2);
+	MLX5_SET(transport_static_params, ctx, acc_type,
+		 MLX5_TRANSPORT_STATIC_PARAMS_ACC_TYPE_NVMETCP);
+	MLX5_SET(transport_static_params, ctx, nvme_resync_tcp_sn, resync_seq);
+	MLX5_SET(transport_static_params, ctx, pda, queue->pda);
+	MLX5_SET(transport_static_params, ctx, ddgst_en, queue->dgst);
+	MLX5_SET(transport_static_params, ctx, ddgst_offload_en, ddgst_offload_en);
+	MLX5_SET(transport_static_params, ctx, hddgst_en, 0);
+	MLX5_SET(transport_static_params, ctx, hdgst_offload_en, 0);
+	MLX5_SET(transport_static_params, ctx, ti,
+		 MLX5_TRANSPORT_STATIC_PARAMS_TI_INITIATOR);
+	MLX5_SET(transport_static_params, ctx, const1, 1);
+	MLX5_SET(transport_static_params, ctx, zero_copy_en, zero_copy_en);
+}
+
+void
+build_nvmeotcp_static_params(struct mlx5e_nvmeotcp_queue *queue,
+			     struct mlx5e_set_nvmeotcp_static_params_wqe *wqe,
+			     u32 resync_seq, bool zerocopy, bool crc_rx)
+{
+	u8 opc_mod = MLX5_CTRL_SEGMENT_OPC_MOD_UMR_NVMEOTCP_TIR_STATIC_PARAMS;
+	struct mlx5_wqe_umr_ctrl_seg *ucseg = &wqe->uctrl;
+	struct mlx5_wqe_ctrl_seg      *cseg = &wqe->ctrl;
+	u32 sqn = queue->sq->icosq.sqn;
+	u16 pc = queue->sq->icosq.pc;
+
+	memset(wqe, 0, MLX5E_NVMEOTCP_STATIC_PARAMS_WQE_SZ);
+
+	cseg->opmod_idx_opcode = cpu_to_be32((pc << MLX5_WQE_CTRL_WQE_INDEX_SHIFT) |
+					     MLX5_OPCODE_UMR | (opc_mod) << 24);
+	cseg->qpn_ds = cpu_to_be32((sqn << MLX5_WQE_CTRL_QPN_SHIFT) |
+				   STATIC_PARAMS_DS_CNT);
+	cseg->imm = cpu_to_be32(queue->tirn << MLX5_WQE_CTRL_TIR_TIS_INDEX_SHIFT);
+
+	ucseg->flags = MLX5_UMR_INLINE;
+	ucseg->bsf_octowords =
+		cpu_to_be16(MLX5E_NVMEOTCP_STATIC_PARAMS_OCTWORD_SIZE);
+	fill_nvmeotcp_static_params(queue, &wqe->params, resync_seq, zerocopy, crc_rx);
 }
 
 static void
 mlx5e_nvmeotcp_fill_wi(struct mlx5e_nvmeotcp_queue *nvmeotcp_queue,
-		       struct mlx5e_icosq *sq, u32 wqe_bbs, u16 pi)
+		       struct mlx5e_icosq *sq, u32 wqe_bbs, u16 pi,
+		       enum wqe_type type)
 {
 	struct mlx5e_icosq_wqe_info *wi = &sq->db.wqe_info[pi];
 
 	wi->num_wqebbs = wqe_bbs;
-	wi->wqe_type = MLX5E_ICOSQ_WQE_UMR_NVME_TCP;
+	switch (type) {
+	case SET_PSV_UMR:
+		wi->wqe_type = MLX5E_ICOSQ_WQE_SET_PSV_NVME_TCP;
+		break;
+	default:
+		wi->wqe_type = MLX5E_ICOSQ_WQE_UMR_NVME_TCP;
+		break;
+	}
+
+	if (type == SET_PSV_UMR)
+		wi->nvmeotcp_q.queue = nvmeotcp_queue;
+}
+
+static void
+mlx5e_nvmeotcp_rx_post_static_params_wqe(struct mlx5e_nvmeotcp_queue *queue,
+					 u32 resync_seq)
+{
+	struct mlx5e_set_nvmeotcp_static_params_wqe *wqe;
+	struct mlx5e_icosq *sq = &queue->sq->icosq;
+	u16 pi, wqe_bbs;
+
+	wqe_bbs = MLX5E_NVMEOTCP_STATIC_PARAMS_WQEBBS;
+	pi = mlx5e_icosq_get_next_pi(sq, wqe_bbs);
+	wqe = MLX5E_NVMEOTCP_FETCH_STATIC_PARAMS_WQE(sq, pi);
+	mlx5e_nvmeotcp_fill_wi(NULL, sq, wqe_bbs, pi, BSF_UMR);
+	build_nvmeotcp_static_params(queue, wqe, resync_seq, queue->zerocopy, queue->crc_rx);
+	sq->pc += wqe_bbs;
+	mlx5e_notify_hw(&sq->wq, sq->pc, sq->uar_map, &wqe->ctrl);
+}
+
+static void
+mlx5e_nvmeotcp_rx_post_progress_params_wqe(struct mlx5e_nvmeotcp_queue *queue,
+					   u32 seq)
+{
+	struct mlx5e_set_nvmeotcp_progress_params_wqe *wqe;
+	struct mlx5e_icosq *sq = &queue->sq->icosq;
+	u16 pi, wqe_bbs;
+
+	wqe_bbs = MLX5E_NVMEOTCP_PROGRESS_PARAMS_WQEBBS;
+	pi = mlx5e_icosq_get_next_pi(sq, wqe_bbs);
+	wqe = MLX5E_NVMEOTCP_FETCH_PROGRESS_PARAMS_WQE(sq, pi);
+	mlx5e_nvmeotcp_fill_wi(queue, sq, wqe_bbs, pi, SET_PSV_UMR);
+	build_nvmeotcp_progress_params(queue, wqe, seq);
+	sq->pc += wqe_bbs;
+	mlx5e_notify_hw(&sq->wq, sq->pc, sq->uar_map, &wqe->ctrl);
 }
 
 static void
 post_klm_wqe(struct mlx5e_nvmeotcp_queue *queue,
+	     enum wqe_type wqe_type,
 	     u16 ccid,
 	     u32 klm_length,
 	     u32 *klm_offset)
@@ -102,9 +377,9 @@ post_klm_wqe(struct mlx5e_nvmeotcp_queue *queue,
 	wqe_bbs = DIV_ROUND_UP(wqe_sz, MLX5_SEND_WQE_BB);
 	pi = mlx5e_icosq_get_next_pi(sq, wqe_bbs);
 	wqe = MLX5E_NVMEOTCP_FETCH_KLM_WQE(sq, pi);
-	mlx5e_nvmeotcp_fill_wi(queue, sq, wqe_bbs, pi);
+	mlx5e_nvmeotcp_fill_wi(queue, sq, wqe_bbs, pi, wqe_type);
 	build_nvmeotcp_klm_umr(queue, wqe, ccid, cur_klm_entries, *klm_offset,
-			       klm_length);
+			       klm_length, wqe_type);
 	*klm_offset += cur_klm_entries;
 	sq->pc += wqe_bbs;
 	sq->doorbell_cseg = &wqe->ctrl;
@@ -112,6 +387,7 @@ post_klm_wqe(struct mlx5e_nvmeotcp_queue *queue,
 
 static int
 mlx5e_nvmeotcp_post_klm_wqe(struct mlx5e_nvmeotcp_queue *queue,
+			    enum wqe_type wqe_type,
 			    u16 ccid,
 			    u32 klm_length)
 {
@@ -129,31 +405,326 @@ mlx5e_nvmeotcp_post_klm_wqe(struct mlx5e_nvmeotcp_queue *queue,
 		return -ENOSPC;
 
 	for (i = 0; i < wqes; i++)
-		post_klm_wqe(queue, ccid, klm_length, &klm_offset);
+		post_klm_wqe(queue, wqe_type, ccid, klm_length, &klm_offset);
 
 	mlx5e_notify_hw(&sq->wq, sq->pc, sq->uar_map, sq->doorbell_cseg);
 	return 0;
 }
 
+static int mlx5e_create_nvmeotcp_mkey(struct mlx5_core_dev *mdev,
+				      u8 access_mode,
+				      u32 translation_octword_size,
+				      struct mlx5_core_mkey *mkey)
+{
+	int inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
+	void *mkc;
+	u32 *in;
+	int err;
+
+	in = kvzalloc(inlen, GFP_KERNEL);
+	if (!in)
+		return -ENOMEM;
+
+	mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
+	MLX5_SET(mkc, mkc, free, 1);
+	MLX5_SET(mkc, mkc, translations_octword_size, translation_octword_size);
+	MLX5_SET(mkc, mkc, umr_en, 1);
+	MLX5_SET(mkc, mkc, lw, 1);
+	MLX5_SET(mkc, mkc, lr, 1);
+	MLX5_SET(mkc, mkc, access_mode_1_0, access_mode);
+
+	MLX5_SET(mkc, mkc, qpn, 0xffffff);
+	MLX5_SET(mkc, mkc, pd, mdev->mlx5e_res.pdn);
+
+	err = mlx5_core_create_mkey(mdev, mkey, in, inlen);
+
+	kvfree(in);
+	return err;
+}
+
 static int
 mlx5e_nvmeotcp_offload_limits(struct net_device *netdev,
 			      struct tcp_ddp_limits *limits)
 {
+	struct mlx5e_priv *priv = netdev_priv(netdev);
+	struct mlx5_core_dev *mdev = priv->mdev;
+
+	limits->max_ddp_sgl_len = mlx5e_get_max_sgl(mdev);
+	return 0;
+}
+
+static void
+mlx5e_nvmeotcp_destroy_sq(struct mlx5e_nvmeotcp_sq *nvmeotcpsq)
+{
+	mlx5e_deactivate_icosq(&nvmeotcpsq->icosq);
+	mlx5e_close_icosq(&nvmeotcpsq->icosq);
+	mlx5e_close_cq(&nvmeotcpsq->icosq.cq);
+	list_del(&nvmeotcpsq->list);
+	kfree(nvmeotcpsq);
+}
+
+static int
+mlx5e_nvmeotcp_build_icosq(struct mlx5e_nvmeotcp_queue *queue,
+			   struct mlx5e_priv *priv)
+{
+	u16 max_sgl, max_klm_per_wqe, max_umr_per_ccid, sgl_rest, wqebbs_rest;
+	struct mlx5e_channel *c = priv->channels.c[queue->channel_ix];
+	struct mlx5e_sq_param icosq_param = {0};
+	struct dim_cq_moder icocq_moder = {0};
+	struct mlx5e_nvmeotcp_sq *nvmeotcp_sq;
+	struct mlx5e_create_cq_param ccp;
+	struct mlx5e_icosq *icosq;
+	int err = -ENOMEM;
+	u16 log_icosq_sz;
+	u32 max_wqebbs;
+
+	nvmeotcp_sq = kzalloc(sizeof(*nvmeotcp_sq), GFP_KERNEL);
+	if (!nvmeotcp_sq)
+		return err;
+
+	icosq = &nvmeotcp_sq->icosq;
+	max_sgl = mlx5e_get_max_sgl(priv->mdev);
+	max_klm_per_wqe = queue->max_klms_per_wqe;
+	max_umr_per_ccid = max_sgl / max_klm_per_wqe;
+	sgl_rest = max_sgl % max_klm_per_wqe;
+	wqebbs_rest = sgl_rest ? MLX5E_KLM_UMR_WQEBBS(sgl_rest) : 0;
+	max_wqebbs = (MLX5E_KLM_UMR_WQEBBS(max_klm_per_wqe) *
+		     max_umr_per_ccid + wqebbs_rest) * queue->size;
+	log_icosq_sz = order_base_2(max_wqebbs);
+
+	mlx5e_build_icosq_param(priv, log_icosq_sz, &icosq_param);
+	mlx5e_build_create_cq_param(&ccp, c);
+	err = mlx5e_open_cq(priv, icocq_moder, &icosq_param.cqp, &ccp, &icosq->cq);
+	if (err)
+		goto err_nvmeotcp_sq;
+
+	err = mlx5e_open_icosq(c, &priv->channels.params, &icosq_param, icosq);
+	if (err)
+		goto close_cq;
+
+	INIT_LIST_HEAD(&nvmeotcp_sq->list);
+	spin_lock(&c->nvmeotcp_icosq_lock);
+	list_add(&nvmeotcp_sq->list, &c->list_nvmeotcpsq);
+	spin_unlock(&c->nvmeotcp_icosq_lock);
+	queue->sq = nvmeotcp_sq;
+	mlx5e_activate_icosq(icosq);
+	return 0;
+
+close_cq:
+	mlx5e_close_cq(&icosq->cq);
+err_nvmeotcp_sq:
+	kfree(nvmeotcp_sq);
+
+	return err;
+}
+
+static void
+mlx5e_nvmeotcp_destroy_rx(struct mlx5e_nvmeotcp_queue *queue,
+			  struct mlx5_core_dev *mdev, bool zerocopy)
+{
+	int i;
+
+	mlx5e_accel_fs_del_sk(queue->fh);
+	for (i = 0; i < queue->size && zerocopy; i++)
+		mlx5_core_destroy_mkey(mdev, &queue->ccid_table[i].klm_mkey);
+
+	mlx5e_nvmeotcp_destroy_tir(queue->priv, queue->tirn);
+	if (zerocopy) {
+		kfree(queue->ccid_table);
+		mlx5_destroy_nvmeotcp_tag_buf_table(mdev, queue->tag_buf_table_id);
+	}
+
+	mlx5e_nvmeotcp_destroy_sq(queue->sq);
+}
+
+static int
+mlx5e_nvmeotcp_queue_rx_init(struct mlx5e_nvmeotcp_queue *queue,
+			     struct nvme_tcp_ddp_config *config,
+			     struct net_device *netdev,
+			     bool zerocopy, bool crc)
+{
+	u8 log_queue_size = order_base_2(config->queue_size);
+	struct mlx5e_priv *priv = netdev_priv(netdev);
+	struct mlx5_core_dev *mdev = priv->mdev;
+	struct sock *sk = queue->sk;
+	int err, max_sgls, i;
+
+	if (zerocopy) {
+		if (config->queue_size >
+		    BIT(MLX5_CAP_DEV_NVMEOTCP(mdev, log_max_nvmeotcp_tag_buffer_size))) {
+			return -EINVAL;
+		}
+
+		err = mlx5e_create_nvmeotcp_tag_buf_table(mdev, queue, log_queue_size);
+		if (err)
+			return err;
+	}
+
+	err = mlx5e_nvmeotcp_build_icosq(queue, priv);
+	if (err)
+		goto destroy_tag_buffer_table;
+
+	/* initializes queue->tirn */
+	err = mlx5e_nvmeotcp_create_tir(priv, sk, config, queue, zerocopy, crc);
+	if (err)
+		goto destroy_icosq;
+
+	mlx5e_nvmeotcp_rx_post_static_params_wqe(queue, 0);
+	mlx5e_nvmeotcp_rx_post_progress_params_wqe(queue, tcp_sk(sk)->copied_seq);
+
+	if (zerocopy) {
+		queue->ccid_table = kcalloc(queue->size,
+					    sizeof(struct nvmeotcp_queue_entry),
+					    GFP_KERNEL);
+		if (!queue->ccid_table) {
+			err = -ENOMEM;
+			goto destroy_tir;
+		}
+
+		max_sgls = mlx5e_get_max_sgl(mdev);
+		for (i = 0; i < queue->size; i++) {
+			err = mlx5e_create_nvmeotcp_mkey(mdev,
+							 MLX5_MKC_ACCESS_MODE_KLMS,
+							 max_sgls,
+							 &queue->ccid_table[i].klm_mkey);
+			if (err)
+				goto free_sgl;
+		}
+
+		err = mlx5e_nvmeotcp_post_klm_wqe(queue, BSF_KLM_UMR, 0, queue->size);
+		if (err)
+			goto free_sgl;
+	}
+
+	if (!(WARN_ON(!wait_for_completion_timeout(&queue->done, 0))))
+		queue->fh = mlx5e_accel_fs_add_sk(priv, sk, queue->tirn, queue->id);
+
+	if (IS_ERR_OR_NULL(queue->fh)) {
+		err = -EINVAL;
+		goto free_sgl;
+	}
+
 	return 0;
+
+free_sgl:
+	while ((i--) && zerocopy)
+		mlx5_core_destroy_mkey(mdev, &queue->ccid_table[i].klm_mkey);
+
+	if (zerocopy)
+		kfree(queue->ccid_table);
+destroy_tir:
+	mlx5e_nvmeotcp_destroy_tir(priv, queue->tirn);
+destroy_icosq:
+	mlx5e_nvmeotcp_destroy_sq(queue->sq);
+destroy_tag_buffer_table:
+	if (zerocopy)
+		mlx5_destroy_nvmeotcp_tag_buf_table(mdev, queue->tag_buf_table_id);
+
+	return err;
 }
 
+#define OCTWORD_SHIFT 4
+#define MAX_DS_VALUE 63
 static int
 mlx5e_nvmeotcp_queue_init(struct net_device *netdev,
 			  struct sock *sk,
 			  struct tcp_ddp_config *tconfig)
 {
-	return 0;
+	struct nvme_tcp_ddp_config *config = (struct nvme_tcp_ddp_config *)tconfig;
+	bool crc_rx = (netdev->features & NETIF_F_HW_TCP_DDP_CRC_RX);
+	bool zerocopy = (netdev->features & NETIF_F_HW_TCP_DDP);
+	struct mlx5e_priv *priv = netdev_priv(netdev);
+	struct mlx5_core_dev *mdev = priv->mdev;
+	struct mlx5e_nvmeotcp_queue *queue;
+	int max_wqe_sz_cap, queue_id, err;
+
+	if (tconfig->type != TCP_DDP_NVME) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	queue = kzalloc(sizeof(*queue), GFP_KERNEL);
+	if (!queue) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	queue_id = ida_simple_get(&priv->nvmeotcp->queue_ids,
+				  MIN_NVMEOTCP_QUEUES, MAX_NVMEOTCP_QUEUES,
+				  GFP_KERNEL);
+	if (queue_id < 0) {
+		err = -ENOSPC;
+		goto free_queue;
+	}
+
+	queue->crc_rx = crc_rx;
+	queue->zerocopy = zerocopy;
+	queue->tcp_ddp_ctx.type = TCP_DDP_NVME;
+	queue->sk = sk;
+	queue->id = queue_id;
+	queue->dgst = config->dgst;
+	queue->pda = config->cpda;
+	queue->channel_ix = mlx5e_get_channel_ix_from_io_cpu(priv,
+							     config->io_cpu);
+	queue->size = config->queue_size;
+	max_wqe_sz_cap  = min_t(int, MAX_DS_VALUE * MLX5_SEND_WQE_DS,
+				MLX5_CAP_GEN(mdev, max_wqe_sz_sq) << OCTWORD_SHIFT);
+	queue->max_klms_per_wqe = MLX5E_KLM_ENTRIES_PER_WQE(max_wqe_sz_cap);
+	queue->priv = priv;
+	init_completion(&queue->done);
+
+	if (zerocopy || crc_rx) {
+		err = mlx5e_nvmeotcp_queue_rx_init(queue, config, netdev,
+						   zerocopy, crc_rx);
+		if (err)
+			goto remove_queue_id;
+	}
+
+	err = rhashtable_insert_fast(&priv->nvmeotcp->queue_hash, &queue->hash,
+				     rhash_queues);
+	if (err)
+		goto destroy_rx;
+
+	write_lock_bh(&sk->sk_callback_lock);
+	tcp_ddp_set_ctx(sk, queue);
+	write_unlock_bh(&sk->sk_callback_lock);
+	refcount_set(&queue->ref_count, 1);
+	return err;
+
+destroy_rx:
+	if (zerocopy || crc_rx)
+		mlx5e_nvmeotcp_destroy_rx(queue, mdev, zerocopy);
+remove_queue_id:
+	ida_simple_remove(&priv->nvmeotcp->queue_ids, queue_id);
+free_queue:
+	kfree(queue);
+out:
+	return err;
 }
 
 static void
 mlx5e_nvmeotcp_queue_teardown(struct net_device *netdev,
 			      struct sock *sk)
 {
+	struct mlx5e_priv *priv = netdev_priv(netdev);
+	struct mlx5_core_dev *mdev = priv->mdev;
+	struct mlx5e_nvmeotcp_queue *queue;
+
+	queue = container_of(tcp_ddp_get_ctx(sk), struct mlx5e_nvmeotcp_queue, tcp_ddp_ctx);
+
+	napi_synchronize(&priv->channels.c[queue->channel_ix]->napi);
+
+	WARN_ON(refcount_read(&queue->ref_count) != 1);
+	if (queue->zerocopy | queue->crc_rx)
+		mlx5e_nvmeotcp_destroy_rx(queue, mdev, queue->zerocopy);
+
+	rhashtable_remove_fast(&priv->nvmeotcp->queue_hash, &queue->hash,
+			       rhash_queues);
+	ida_simple_remove(&priv->nvmeotcp->queue_ids, queue->id);
+	write_lock_bh(&sk->sk_callback_lock);
+	tcp_ddp_set_ctx(sk, NULL);
+	write_unlock_bh(&sk->sk_callback_lock);
+	mlx5e_nvmeotcp_put_queue(queue);
 }
 
 static int
@@ -164,6 +735,16 @@ mlx5e_nvmeotcp_ddp_setup(struct net_device *netdev,
 	return 0;
 }
 
+void mlx5e_nvmeotcp_ctx_comp(struct mlx5e_icosq_wqe_info *wi)
+{
+	struct mlx5e_nvmeotcp_queue *queue = wi->nvmeotcp_q.queue;
+
+	if (unlikely(!queue))
+		return;
+
+	complete(&queue->done);
+}
+
 static int
 mlx5e_nvmeotcp_ddp_teardown(struct net_device *netdev,
 			    struct sock *sk,
@@ -188,6 +769,27 @@ static const struct tcp_ddp_dev_ops mlx5e_nvmeotcp_ops = {
 	.tcp_ddp_resync = mlx5e_nvmeotcp_dev_resync,
 };
 
+struct mlx5e_nvmeotcp_queue *
+mlx5e_nvmeotcp_get_queue(struct mlx5e_nvmeotcp *nvmeotcp, int id)
+{
+	struct mlx5e_nvmeotcp_queue *queue;
+
+	rcu_read_lock();
+	queue = rhashtable_lookup_fast(&nvmeotcp->queue_hash,
+				       &id, rhash_queues);
+	if (queue && !IS_ERR(queue))
+		if (!refcount_inc_not_zero(&queue->ref_count))
+			queue = NULL;
+	rcu_read_unlock();
+	return queue;
+}
+
+void mlx5e_nvmeotcp_put_queue(struct mlx5e_nvmeotcp_queue *queue)
+{
+	if (refcount_dec_and_test(&queue->ref_count))
+		kfree(queue);
+}
+
 int set_feature_nvme_tcp(struct net_device *netdev, bool enable)
 {
 	struct mlx5e_priv *priv = netdev_priv(netdev);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.h
index 753757fc44a3..d0e515502d6d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.h
@@ -100,6 +100,10 @@ int mlx5e_nvmeotcp_init(struct mlx5e_priv *priv);
 int set_feature_nvme_tcp(struct net_device *netdev, bool enable);
 int set_feature_nvme_tcp_crc(struct net_device *netdev, bool enable);
 void mlx5e_nvmeotcp_cleanup(struct mlx5e_priv *priv);
+struct mlx5e_nvmeotcp_queue *
+mlx5e_nvmeotcp_get_queue(struct mlx5e_nvmeotcp *nvmeotcp, int id);
+void mlx5e_nvmeotcp_put_queue(struct mlx5e_nvmeotcp_queue *queue);
+void mlx5e_nvmeotcp_ctx_comp(struct mlx5e_icosq_wqe_info *wi);
 int mlx5e_nvmeotcp_init_rx(struct mlx5e_priv *priv);
 void mlx5e_nvmeotcp_cleanup_rx(struct mlx5e_priv *priv);
 #else
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp_utils.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp_utils.h
index 329e114d6571..44671e28a9ea 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp_utils.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp_utils.h
@@ -4,9 +4,77 @@
 #define __MLX5E_NVMEOTCP_UTILS_H__
 
 #include "en.h"
+#include "en_accel/nvmeotcp.h"
+
+enum {
+	MLX5E_NVMEOTCP_PROGRESS_PARAMS_PDU_TRACKER_STATE_START     = 0,
+	MLX5E_NVMEOTCP_PROGRESS_PARAMS_PDU_TRACKER_STATE_TRACKING  = 1,
+	MLX5E_NVMEOTCP_PROGRESS_PARAMS_PDU_TRACKER_STATE_SEARCHING = 2,
+};
+
+struct mlx5_seg_nvmeotcp_static_params {
+	u8     ctx[MLX5_ST_SZ_BYTES(transport_static_params)];
+};
+
+struct mlx5_seg_nvmeotcp_progress_params {
+	__be32 tir_num;
+	u8     ctx[MLX5_ST_SZ_BYTES(nvmeotcp_progress_params)];
+};
+
+struct mlx5e_set_nvmeotcp_static_params_wqe {
+	struct mlx5_wqe_ctrl_seg          ctrl;
+	struct mlx5_wqe_umr_ctrl_seg      uctrl;
+	struct mlx5_mkey_seg              mkc;
+	struct mlx5_seg_nvmeotcp_static_params params;
+};
+
+struct mlx5e_set_nvmeotcp_progress_params_wqe {
+	struct mlx5_wqe_ctrl_seg            ctrl;
+	struct mlx5_seg_nvmeotcp_progress_params params;
+};
+
+struct mlx5e_get_psv_wqe {
+	struct mlx5_wqe_ctrl_seg ctrl;
+	struct mlx5_seg_get_psv  psv;
+};
+
+///////////////////////////////////////////
+#define MLX5E_NVMEOTCP_STATIC_PARAMS_WQE_SZ \
+	(sizeof(struct mlx5e_set_nvmeotcp_static_params_wqe))
+
+#define MLX5E_NVMEOTCP_PROGRESS_PARAMS_WQE_SZ \
+	(sizeof(struct mlx5e_set_nvmeotcp_progress_params_wqe))
+#define MLX5E_NVMEOTCP_STATIC_PARAMS_OCTWORD_SIZE \
+	(MLX5_ST_SZ_BYTES(transport_static_params) / MLX5_SEND_WQE_DS)
+
+#define MLX5E_NVMEOTCP_STATIC_PARAMS_WQEBBS \
+	(DIV_ROUND_UP(MLX5E_NVMEOTCP_STATIC_PARAMS_WQE_SZ, MLX5_SEND_WQE_BB))
+#define MLX5E_NVMEOTCP_PROGRESS_PARAMS_WQEBBS \
+	(DIV_ROUND_UP(MLX5E_NVMEOTCP_PROGRESS_PARAMS_WQE_SZ, MLX5_SEND_WQE_BB))
+
+#define MLX5E_NVMEOTCP_FETCH_STATIC_PARAMS_WQE(sq, pi) \
+	((struct mlx5e_set_nvmeotcp_static_params_wqe *)\
+	 mlx5e_fetch_wqe(&(sq)->wq, pi, sizeof(struct mlx5e_set_nvmeotcp_static_params_wqe)))
+
+#define MLX5E_NVMEOTCP_FETCH_PROGRESS_PARAMS_WQE(sq, pi) \
+	((struct mlx5e_set_nvmeotcp_progress_params_wqe *)\
+	 mlx5e_fetch_wqe(&(sq)->wq, pi, sizeof(struct mlx5e_set_nvmeotcp_progress_params_wqe)))
 
 #define MLX5E_NVMEOTCP_FETCH_KLM_WQE(sq, pi) \
 	((struct mlx5e_umr_wqe *)\
 	 mlx5e_fetch_wqe(&(sq)->wq, pi, sizeof(struct mlx5e_umr_wqe)))
 
+#define MLX5_CTRL_SEGMENT_OPC_MOD_UMR_NVMEOTCP_TIR_PROGRESS_PARAMS 0x4
+
+void
+build_nvmeotcp_progress_params(struct mlx5e_nvmeotcp_queue *queue,
+			       struct mlx5e_set_nvmeotcp_progress_params_wqe *wqe,
+			       u32 seq);
+
+void
+build_nvmeotcp_static_params(struct mlx5e_nvmeotcp_queue *queue,
+			     struct mlx5e_set_nvmeotcp_static_params_wqe *wqe,
+			     u32 resync_seq,
+			     bool zerocopy, bool crc_rx);
+
 #endif /* __MLX5E_NVMEOTCP_UTILS_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
index 28aa99265c0a..056fc24dd5ed 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -47,6 +47,7 @@
 #include "fpga/ipsec.h"
 #include "en_accel/ipsec_rxtx.h"
 #include "en_accel/tls_rxtx.h"
+#include "en_accel/nvmeotcp.h"
 #include "lib/clock.h"
 #include "en/xdp.h"
 #include "en/xsk/rx.h"
@@ -629,6 +630,9 @@ void mlx5e_free_icosq_descs(struct mlx5e_icosq *sq)
 #ifdef CONFIG_MLX5_EN_NVMEOTCP
 		case MLX5E_ICOSQ_WQE_UMR_NVME_TCP:
 			break;
+		case MLX5E_ICOSQ_WQE_SET_PSV_NVME_TCP:
+			mlx5e_nvmeotcp_ctx_comp(wi);
+			break;
 #endif
 		}
 	}
@@ -703,6 +707,9 @@ int mlx5e_poll_ico_cq(struct mlx5e_cq *cq)
 #ifdef CONFIG_MLX5_EN_NVMEOTCP
 			case MLX5E_ICOSQ_WQE_UMR_NVME_TCP:
 				break;
+			case MLX5E_ICOSQ_WQE_SET_PSV_NVME_TCP:
+				mlx5e_nvmeotcp_ctx_comp(wi);
+				break;
 #endif
 			default:
 				netdev_WARN_ONCE(cq->netdev,
-- 
2.24.1



From borisp at mellanox.com  Thu Jan 14 10:10:25 2021
From: borisp at mellanox.com (Boris Pismenny)
Date: Thu, 14 Jan 2021 17:10:25 +0200
Subject: [PATCH v2 net-next 13/21] net/mlx5e: NVMEoTCP offload initialization
In-Reply-To: <20210114151033.13020-1-borisp@mellanox.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
Message-ID: <20210114151033.13020-14-borisp@mellanox.com>

From: Ben Ben-Ishay <benishay at nvidia.com>

This commit introduce the initialization blocks for NVMEoTCP offload:
- Use 128B CQEs when NVME-TCP offload is enabled.
- Use a dedicated icosq for NVME-TCP work. This list of SQ is unique in the
  sense that it is driven directly by the NVME-TCP layer to submit and
  invalidate ddp requests.
- Query nvmeotcp capabilities

Signed-off-by: Boris Pismenny <borisp at mellanox.com>
Signed-off-by: Ben Ben-Ishay <benishay at nvidia.com>
Signed-off-by: Or Gerlitz <ogerlitz at mellanox.com>
Signed-off-by: Yoray Zack <yorayz at mellanox.com>
---
 .../net/ethernet/mellanox/mlx5/core/Kconfig   |  11 +
 .../net/ethernet/mellanox/mlx5/core/Makefile  |   2 +
 drivers/net/ethernet/mellanox/mlx5/core/en.h  |   7 +
 .../ethernet/mellanox/mlx5/core/en/params.h   |   1 +
 .../mellanox/mlx5/core/en_accel/en_accel.h    |   9 +-
 .../mellanox/mlx5/core/en_accel/nvmeotcp.c    | 196 ++++++++++++++++++
 .../mellanox/mlx5/core/en_accel/nvmeotcp.h    | 115 ++++++++++
 .../net/ethernet/mellanox/mlx5/core/en_main.c |  39 +++-
 .../net/ethernet/mellanox/mlx5/core/en_txrx.c |  17 ++
 drivers/net/ethernet/mellanox/mlx5/core/fw.c  |   6 +
 10 files changed, 401 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.c
 create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.h

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig
index ad45d20f9d44..02b4066f54e6 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig
+++ b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig
@@ -222,3 +222,14 @@ config MLX5_SF_MANAGER
 	port is managed through devlink.  A subfunction supports RDMA, netdevice
 	and vdpa device. It is similar to a SRIOV VF but it doesn't require
 	SRIOV support.
+
+config MLX5_EN_NVMEOTCP
+	bool "NVMEoTCP accelaration"
+	depends on MLX5_CORE_EN
+	depends on TCP_DDP
+	depends on TCP_DDP_CRC
+	default y
+	help
+	Build support for NVMEoTCP accelaration in the NIC.
+	Note: Support for hardware with this capability needs to be selected
+	for this option to become available.
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
index 59ed3c39c8c3..ada8cd22f8fb 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
@@ -96,3 +96,5 @@ mlx5_core-$(CONFIG_MLX5_SF) += sf/vhca_event.o sf/dev/dev.o sf/dev/driver.o
 # SF manager
 #
 mlx5_core-$(CONFIG_MLX5_SF_MANAGER) += sf/cmd.o sf/hw_table.o sf/devlink.o
+
+mlx5_core-$(CONFIG_MLX5_EN_NVMEOTCP) += en_accel/fs_tcp.o en_accel/nvmeotcp.o
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
index 01c8115caa64..ff100c290b59 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@ -664,6 +664,10 @@ struct mlx5e_channel {
 	struct mlx5e_xdpsq         rq_xdpsq;
 	struct mlx5e_txqsq         sq[MLX5E_MAX_NUM_TC];
 	struct mlx5e_icosq         icosq;   /* internal control operations */
+#ifdef CONFIG_MLX5_EN_NVMEOTCP
+	struct list_head	   list_nvmeotcpsq;   /* nvmeotcp umrs  */
+	spinlock_t                 nvmeotcp_icosq_lock;
+#endif
 	bool                       xdp;
 	struct napi_struct         napi;
 	struct device             *pdev;
@@ -856,6 +860,9 @@ struct mlx5e_priv {
 #endif
 #ifdef CONFIG_MLX5_EN_TLS
 	struct mlx5e_tls          *tls;
+#endif
+#ifdef CONFIG_MLX5_EN_NVMEOTCP
+	struct mlx5e_nvmeotcp      *nvmeotcp;
 #endif
 	struct devlink_health_reporter *tx_reporter;
 	struct devlink_health_reporter *rx_reporter;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/params.h b/drivers/net/ethernet/mellanox/mlx5/core/en/params.h
index 807147d97a0f..20e9e5e81ae7 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/params.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/params.h
@@ -16,6 +16,7 @@ struct mlx5e_cq_param {
 	struct mlx5_wq_param       wq;
 	u16                        eq_ix;
 	u8                         cq_period_mode;
+	bool                       force_cqe128;
 };
 
 struct mlx5e_rq_param {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h
index fb89b24deb2b..98728f7404ec 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h
@@ -39,6 +39,7 @@
 #include "en_accel/ipsec_rxtx.h"
 #include "en_accel/tls.h"
 #include "en_accel/tls_rxtx.h"
+#include "en_accel/nvmeotcp.h"
 #include "en.h"
 #include "en/txrx.h"
 
@@ -196,11 +197,17 @@ static inline void mlx5e_accel_tx_finish(struct mlx5e_txqsq *sq,
 
 static inline int mlx5e_accel_init_rx(struct mlx5e_priv *priv)
 {
-	return mlx5e_ktls_init_rx(priv);
+	int tls, nvmeotcp;
+
+	tls = mlx5e_ktls_init_rx(priv);
+	nvmeotcp = mlx5e_nvmeotcp_init_rx(priv);
+
+	return tls && nvmeotcp;
 }
 
 static inline void mlx5e_accel_cleanup_rx(struct mlx5e_priv *priv)
 {
+	mlx5e_nvmeotcp_cleanup_rx(priv);
 	mlx5e_ktls_cleanup_rx(priv);
 }
 #endif /* __MLX5E_EN_ACCEL_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.c
new file mode 100644
index 000000000000..0834deb7a3ac
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.c
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/* Copyright (c) 2021 Mellanox Technologies. */
+
+#include <linux/netdevice.h>
+#include <linux/idr.h>
+#include "en_accel/nvmeotcp.h"
+#include "en_accel/fs_tcp.h"
+#include "en/txrx.h"
+
+#define MAX_NVMEOTCP_QUEUES	(512)
+#define MIN_NVMEOTCP_QUEUES	(1)
+
+static const struct rhashtable_params rhash_queues = {
+	.key_len = sizeof(int),
+	.key_offset = offsetof(struct mlx5e_nvmeotcp_queue, id),
+	.head_offset = offsetof(struct mlx5e_nvmeotcp_queue, hash),
+	.automatic_shrinking = true,
+	.min_size = 1,
+	.max_size = MAX_NVMEOTCP_QUEUES,
+};
+
+static int
+mlx5e_nvmeotcp_offload_limits(struct net_device *netdev,
+			      struct tcp_ddp_limits *limits)
+{
+	return 0;
+}
+
+static int
+mlx5e_nvmeotcp_queue_init(struct net_device *netdev,
+			  struct sock *sk,
+			  struct tcp_ddp_config *tconfig)
+{
+	return 0;
+}
+
+static void
+mlx5e_nvmeotcp_queue_teardown(struct net_device *netdev,
+			      struct sock *sk)
+{
+}
+
+static int
+mlx5e_nvmeotcp_ddp_setup(struct net_device *netdev,
+			 struct sock *sk,
+			 struct tcp_ddp_io *ddp)
+{
+	return 0;
+}
+
+static int
+mlx5e_nvmeotcp_ddp_teardown(struct net_device *netdev,
+			    struct sock *sk,
+			    struct tcp_ddp_io *ddp,
+			    void *ddp_ctx)
+{
+	return 0;
+}
+
+static void
+mlx5e_nvmeotcp_dev_resync(struct net_device *netdev,
+			  struct sock *sk, u32 seq)
+{
+}
+
+static const struct tcp_ddp_dev_ops mlx5e_nvmeotcp_ops = {
+	.tcp_ddp_limits = mlx5e_nvmeotcp_offload_limits,
+	.tcp_ddp_sk_add = mlx5e_nvmeotcp_queue_init,
+	.tcp_ddp_sk_del = mlx5e_nvmeotcp_queue_teardown,
+	.tcp_ddp_setup = mlx5e_nvmeotcp_ddp_setup,
+	.tcp_ddp_teardown = mlx5e_nvmeotcp_ddp_teardown,
+	.tcp_ddp_resync = mlx5e_nvmeotcp_dev_resync,
+};
+
+int set_feature_nvme_tcp(struct net_device *netdev, bool enable)
+{
+	struct mlx5e_priv *priv = netdev_priv(netdev);
+	int err = 0;
+
+	mutex_lock(&priv->state_lock);
+	if (enable)
+		err = mlx5e_accel_fs_tcp_create(priv);
+	else
+		mlx5e_accel_fs_tcp_destroy(priv);
+	mutex_unlock(&priv->state_lock);
+	if (err)
+		return err;
+
+	priv->nvmeotcp->enable = enable;
+	err = mlx5e_safe_reopen_channels(priv);
+	return err;
+}
+
+int set_feature_nvme_tcp_crc(struct net_device *netdev, bool enable)
+{
+	struct mlx5e_priv *priv = netdev_priv(netdev);
+	int err = 0;
+
+	mutex_lock(&priv->state_lock);
+	if (enable)
+		err = mlx5e_accel_fs_tcp_create(priv);
+	else
+		mlx5e_accel_fs_tcp_destroy(priv);
+	mutex_unlock(&priv->state_lock);
+
+	priv->nvmeotcp->crc_rx_enable = enable;
+	err = mlx5e_safe_reopen_channels(priv);
+	if (err)
+		netdev_err(priv->netdev,
+			   "%s failed to reopen channels, err(%d).\n",
+			   __func__, err);
+
+	return err;
+}
+
+void mlx5e_nvmeotcp_build_netdev(struct mlx5e_priv *priv)
+{
+	struct net_device *netdev = priv->netdev;
+
+	if (!MLX5_CAP_GEN(priv->mdev, nvmeotcp))
+		return;
+
+	if (MLX5_CAP_DEV_NVMEOTCP(priv->mdev, zerocopy)) {
+		netdev->features |= NETIF_F_HW_TCP_DDP;
+		netdev->hw_features |= NETIF_F_HW_TCP_DDP;
+	}
+
+	if (MLX5_CAP_DEV_NVMEOTCP(priv->mdev, crc_rx)) {
+		netdev->features |= NETIF_F_HW_TCP_DDP_CRC_RX;
+		netdev->hw_features |= NETIF_F_HW_TCP_DDP_CRC_RX;
+	}
+
+	netdev->tcp_ddp_ops = &mlx5e_nvmeotcp_ops;
+	priv->nvmeotcp->enable = true;
+}
+
+int mlx5e_nvmeotcp_init_rx(struct mlx5e_priv *priv)
+{
+	int ret = 0;
+
+	if (priv->netdev->features & NETIF_F_HW_TCP_DDP) {
+		ret = mlx5e_accel_fs_tcp_create(priv);
+		if (ret)
+			return ret;
+	}
+
+	if (priv->netdev->features & NETIF_F_HW_TCP_DDP_CRC_RX)
+		ret = mlx5e_accel_fs_tcp_create(priv);
+
+	return ret;
+}
+
+void mlx5e_nvmeotcp_cleanup_rx(struct mlx5e_priv *priv)
+{
+	if (priv->netdev->features & NETIF_F_HW_TCP_DDP)
+		mlx5e_accel_fs_tcp_destroy(priv);
+
+	if (priv->netdev->features & NETIF_F_HW_TCP_DDP_CRC_RX)
+		mlx5e_accel_fs_tcp_destroy(priv);
+}
+
+int mlx5e_nvmeotcp_init(struct mlx5e_priv *priv)
+{
+	struct mlx5e_nvmeotcp *nvmeotcp = kzalloc(sizeof(*nvmeotcp), GFP_KERNEL);
+	int ret = 0;
+
+	if (!nvmeotcp)
+		return -ENOMEM;
+
+	ida_init(&nvmeotcp->queue_ids);
+	ret = rhashtable_init(&nvmeotcp->queue_hash, &rhash_queues);
+	if (ret)
+		goto err_ida;
+
+	priv->nvmeotcp = nvmeotcp;
+	goto out;
+
+err_ida:
+	ida_destroy(&nvmeotcp->queue_ids);
+	kfree(nvmeotcp);
+out:
+	return ret;
+}
+
+void mlx5e_nvmeotcp_cleanup(struct mlx5e_priv *priv)
+{
+	struct mlx5e_nvmeotcp *nvmeotcp = priv->nvmeotcp;
+
+	if (!nvmeotcp)
+		return;
+
+	rhashtable_destroy(&nvmeotcp->queue_hash);
+	ida_destroy(&nvmeotcp->queue_ids);
+	kfree(nvmeotcp);
+	priv->nvmeotcp = NULL;
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.h
new file mode 100644
index 000000000000..753757fc44a3
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.h
@@ -0,0 +1,115 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2021 Mellanox Technologies. */
+#ifndef __MLX5E_NVMEOTCP_H__
+#define __MLX5E_NVMEOTCP_H__
+
+#ifdef CONFIG_MLX5_EN_NVMEOTCP
+
+#include "net/tcp_ddp.h"
+#include "en.h"
+#include "en/params.h"
+
+struct nvmeotcp_queue_entry {
+	struct mlx5e_nvmeotcp_queue	*queue;
+	u32				sgl_length;
+	struct mlx5_core_mkey		klm_mkey;
+	struct scatterlist		*sgl;
+	u32				ccid_gen;
+	u64				size;
+
+	/* for the ddp invalidate done callback */
+	void				*ddp_ctx;
+	struct tcp_ddp_io		*ddp;
+};
+
+struct mlx5e_nvmeotcp_sq {
+	struct list_head		list;
+	struct mlx5e_icosq		icosq;
+};
+
+/**
+ *	struct mlx5e_nvmeotcp_queue - MLX5 metadata for NVMEoTCP queue
+ *	@fh: Flow handle representing the 5-tuple steering for this flow
+ *	@tirn: Destination TIR number created for NVMEoTCP offload
+ *	@id: Flow tag ID used to identify this queue
+ *	@size: NVMEoTCP queue depth
+ *	@sq: Send queue used for sending control messages
+ *	@ccid_table: Table holding metadata for each CC
+ *	@tag_buf_table_id: Tag buffer table for CCIDs
+ *	@hash: Hash table of queues mapped by @id
+ *	@ref_count: Reference count for this structure
+ *	@ccoff: Offset within the current CC
+ *	@pda: Padding alignment
+ *	@ccid_gen: Generation ID for the CCID, used to avoid conflicts in DDP
+ *	@max_klms_per_wqe: Number of KLMs per DDP operation
+ *	@channel_ix: Channel IX for this nvmeotcp_queue
+ *	@sk: The socket used by the NVMe-TCP queue
+ *	@zerocopy: if this queue is used for zerocopy offload.
+ *	@crc_rx: if this queue is used for CRC Rx offload.
+ *	@ccid: ID of the current CC
+ *	@ccsglidx: Index within the scatter-gather list (SGL) of the current CC
+ *	@ccoff_inner: Current offset within the @ccsglidx element
+ *	@priv: mlx5e netdev priv
+ *	@inv_done: invalidate callback of the nvme tcp driver
+ *	@after_resync_cqe: indicate if resync occurred
+ */
+struct mlx5e_nvmeotcp_queue {
+	struct tcp_ddp_ctx		tcp_ddp_ctx;
+	struct mlx5_flow_handle		*fh;
+	int				tirn;
+	int				id;
+	u32				size;
+	struct mlx5e_nvmeotcp_sq	*sq;
+	struct nvmeotcp_queue_entry	*ccid_table;
+	u32				tag_buf_table_id;
+	struct rhash_head		hash;
+	refcount_t			ref_count;
+	bool				dgst;
+	int				pda;
+	u32				ccid_gen;
+	u32				max_klms_per_wqe;
+	u32				channel_ix;
+	struct sock			*sk;
+	bool				zerocopy;
+	bool				crc_rx;
+
+	/* current ccid fields */
+	off_t				ccoff;
+	int				ccid;
+	int				ccsglidx;
+	int				ccoff_inner;
+
+	/* for ddp invalidate flow */
+	struct mlx5e_priv		*priv;
+
+	/* for flow_steering flow */
+	struct completion		done;
+	/* for MASK HW resync cqe */
+	bool				after_resync_cqe;
+};
+
+struct mlx5e_nvmeotcp {
+	struct ida			queue_ids;
+	struct rhashtable		queue_hash;
+	bool				enable;
+	bool				crc_rx_enable;
+};
+
+void mlx5e_nvmeotcp_build_netdev(struct mlx5e_priv *priv);
+int mlx5e_nvmeotcp_init(struct mlx5e_priv *priv);
+int set_feature_nvme_tcp(struct net_device *netdev, bool enable);
+int set_feature_nvme_tcp_crc(struct net_device *netdev, bool enable);
+void mlx5e_nvmeotcp_cleanup(struct mlx5e_priv *priv);
+int mlx5e_nvmeotcp_init_rx(struct mlx5e_priv *priv);
+void mlx5e_nvmeotcp_cleanup_rx(struct mlx5e_priv *priv);
+#else
+
+static inline void mlx5e_nvmeotcp_build_netdev(struct mlx5e_priv *priv) { }
+static inline int mlx5e_nvmeotcp_init(struct mlx5e_priv *priv) { return 0; }
+static inline void mlx5e_nvmeotcp_cleanup(struct mlx5e_priv *priv) { }
+static inline int set_feature_nvme_tcp(struct net_device *netdev, bool enable) { return 0; }
+static inline int set_feature_nvme_tcp_crc(struct net_device *netdev, bool enable) { return 0; }
+static inline int mlx5e_nvmeotcp_init_rx(struct mlx5e_priv *priv) { return 0; }
+static inline void mlx5e_nvmeotcp_cleanup_rx(struct mlx5e_priv *priv) { }
+#endif
+#endif /* __MLX5E_NVMEOTCP_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index 48566e7d49a7..98fe57531ccc 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -47,6 +47,7 @@
 #include "en_accel/ipsec.h"
 #include "en_accel/en_accel.h"
 #include "en_accel/tls.h"
+#include "en_accel/nvmeotcp.h"
 #include "accel/ipsec.h"
 #include "accel/tls.h"
 #include "lib/vxlan.h"
@@ -2010,6 +2011,10 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix,
 	c->aff_mask = irq_get_effective_affinity_mask(irq);
 	c->lag_port = mlx5e_enumerate_lag_port(priv->mdev, ix);
 
+#ifdef CONFIG_MLX5_EN_NVMEOTCP
+	INIT_LIST_HEAD(&c->list_nvmeotcpsq);
+	spin_lock_init(&c->nvmeotcp_icosq_lock);
+#endif
 	netif_napi_add(netdev, &c->napi, mlx5e_napi_poll, 64);
 
 	err = mlx5e_open_queues(c, params, cparam);
@@ -2246,7 +2251,8 @@ static void mlx5e_build_common_cq_param(struct mlx5e_priv *priv,
 	void *cqc = param->cqc;
 
 	MLX5_SET(cqc, cqc, uar_page, priv->mdev->priv.uar->index);
-	if (MLX5_CAP_GEN(priv->mdev, cqe_128_always) && cache_line_size() >= 128)
+	if (MLX5_CAP_GEN(priv->mdev, cqe_128_always) &&
+	    (cache_line_size() >= 128 || param->force_cqe128))
 		MLX5_SET(cqc, cqc, cqe_sz, CQE_STRIDE_128_PAD);
 }
 
@@ -2260,6 +2266,11 @@ void mlx5e_build_rx_cq_param(struct mlx5e_priv *priv,
 	void *cqc = param->cqc;
 	u8 log_cq_size;
 
+#ifdef CONFIG_MLX5_EN_NVMEOTCP
+	/* nvme-tcp offload mandates 128 byte cqes */
+	param->force_cqe128 |= (priv->nvmeotcp->enable || priv->nvmeotcp->crc_rx_enable);
+#endif
+
 	switch (params->rq_wq_type) {
 	case MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ:
 		log_cq_size = mlx5e_mpwqe_get_log_rq_size(params, xsk) +
@@ -3957,6 +3968,10 @@ int mlx5e_set_features(struct net_device *netdev, netdev_features_t features)
 	err |= MLX5E_HANDLE_FEATURE(NETIF_F_NTUPLE, set_feature_arfs);
 #endif
 	err |= MLX5E_HANDLE_FEATURE(NETIF_F_HW_TLS_RX, mlx5e_ktls_set_feature_rx);
+#ifdef CONFIG_MLX5_EN_NVMEOTCP
+	err |= MLX5E_HANDLE_FEATURE(NETIF_F_HW_TCP_DDP, set_feature_nvme_tcp);
+	err |= MLX5E_HANDLE_FEATURE(NETIF_F_HW_TCP_DDP_CRC_RX, set_feature_nvme_tcp_crc);
+#endif
 
 	if (err) {
 		netdev->features = oper_features;
@@ -3993,6 +4008,23 @@ static netdev_features_t mlx5e_fix_features(struct net_device *netdev,
 		features &= ~NETIF_F_RXHASH;
 		if (netdev->features & NETIF_F_RXHASH)
 			netdev_warn(netdev, "Disabling rxhash, not supported when CQE compress is active\n");
+
+		features &= ~NETIF_F_HW_TCP_DDP;
+		if (netdev->features & NETIF_F_HW_TCP_DDP)
+			netdev_warn(netdev, "Disabling tcp-ddp offload, not supported when CQE compress is active\n");
+
+		features &= ~NETIF_F_HW_TCP_DDP_CRC_RX;
+		if (netdev->features & NETIF_F_HW_TCP_DDP_CRC_RX)
+			netdev_warn(netdev, "Disabling tcp-ddp-crc-rx offload, not supported when CQE compression is active\n");
+	}
+
+	if (netdev->features & NETIF_F_LRO) {
+		features &= ~NETIF_F_HW_TCP_DDP;
+		if (netdev->features & NETIF_F_HW_TCP_DDP)
+			netdev_warn(netdev, "Disabling tcp-ddp offload, not supported when LRO is active\n");
+		features &= ~NETIF_F_HW_TCP_DDP_CRC_RX;
+		if (netdev->features & NETIF_F_HW_TCP_DDP_CRC_RX)
+			netdev_warn(netdev, "Disabling tcp-ddp-crc-rx offload, not supported when LRO is active\n");
 	}
 
 	mutex_unlock(&priv->state_lock);
@@ -5064,6 +5096,7 @@ static void mlx5e_build_nic_netdev(struct net_device *netdev)
 	mlx5e_set_netdev_dev_addr(netdev);
 	mlx5e_ipsec_build_netdev(priv);
 	mlx5e_tls_build_netdev(priv);
+	mlx5e_nvmeotcp_build_netdev(priv);
 }
 
 void mlx5e_create_q_counters(struct mlx5e_priv *priv)
@@ -5128,6 +5161,9 @@ static int mlx5e_nic_init(struct mlx5_core_dev *mdev,
 	err = mlx5e_tls_init(priv);
 	if (err)
 		mlx5_core_err(mdev, "TLS initialization failed, %d\n", err);
+	err = mlx5e_nvmeotcp_init(priv);
+	if (err)
+		mlx5_core_err(mdev, "NVMEoTCP initialization failed, %d\n", err);
 	mlx5e_build_nic_netdev(netdev);
 	err = mlx5e_devlink_port_register(priv);
 	if (err)
@@ -5141,6 +5177,7 @@ static void mlx5e_nic_cleanup(struct mlx5e_priv *priv)
 {
 	mlx5e_health_destroy_reporters(priv);
 	mlx5e_devlink_port_unregister(priv);
+	mlx5e_nvmeotcp_cleanup(priv);
 	mlx5e_tls_cleanup(priv);
 	mlx5e_ipsec_cleanup(priv);
 	mlx5e_netdev_cleanup(priv->netdev, priv);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c
index a3cfe06d5116..aa0dcebe3a97 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c
@@ -36,6 +36,7 @@
 #include "en/xdp.h"
 #include "en/xsk/rx.h"
 #include "en/xsk/tx.h"
+#include "en_accel/nvmeotcp.h"
 
 static inline bool mlx5e_channel_no_affinity_change(struct mlx5e_channel *c)
 {
@@ -117,6 +118,10 @@ int mlx5e_napi_poll(struct napi_struct *napi, int budget)
 	struct mlx5e_xdpsq *xsksq = &c->xsksq;
 	struct mlx5e_rq *xskrq = &c->xskrq;
 	struct mlx5e_rq *rq = &c->rq;
+#ifdef CONFIG_MLX5_EN_NVMEOTCP
+	struct mlx5e_nvmeotcp_sq *nvmeotcp_sq;
+	struct list_head *cur;
+#endif
 	bool aff_change = false;
 	bool busy_xsk = false;
 	bool busy = false;
@@ -154,6 +159,12 @@ int mlx5e_napi_poll(struct napi_struct *napi, int budget)
 		 * queueing more WQEs and overflowing the async ICOSQ.
 		 */
 		clear_bit(MLX5E_SQ_STATE_PENDING_XSK_TX, &c->async_icosq.state);
+#ifdef CONFIG_MLX5_EN_NVMEOTCP
+	list_for_each(cur, &c->list_nvmeotcpsq) {
+		nvmeotcp_sq = list_entry(cur, struct mlx5e_nvmeotcp_sq, list);
+		mlx5e_poll_ico_cq(&nvmeotcp_sq->icosq.cq);
+	}
+#endif
 
 	busy |= INDIRECT_CALL_2(rq->post_wqes,
 				mlx5e_post_rx_mpwqes,
@@ -192,6 +203,12 @@ int mlx5e_napi_poll(struct napi_struct *napi, int budget)
 	mlx5e_cq_arm(&rq->cq);
 	mlx5e_cq_arm(&c->icosq.cq);
 	mlx5e_cq_arm(&c->async_icosq.cq);
+#ifdef CONFIG_MLX5_EN_NVMEOTCP
+	list_for_each(cur, &c->list_nvmeotcpsq) {
+		nvmeotcp_sq = list_entry(cur, struct mlx5e_nvmeotcp_sq, list);
+		mlx5e_cq_arm(&nvmeotcp_sq->icosq.cq);
+	}
+#endif
 	mlx5e_cq_arm(&c->xdpsq.cq);
 
 	if (xsk_open) {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
index 02558ac2ace6..5e7544ccae91 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
@@ -256,6 +256,12 @@ int mlx5_query_hca_caps(struct mlx5_core_dev *dev)
 			return err;
 	}
 
+	if (MLX5_CAP_GEN(dev, nvmeotcp)) {
+		err = mlx5_core_get_caps(dev, MLX5_CAP_DEV_NVMEOTCP);
+		if (err)
+			return err;
+	}
+
 	return 0;
 }
 
-- 
2.24.1



From borisp at mellanox.com  Thu Jan 14 10:10:21 2021
From: borisp at mellanox.com (Boris Pismenny)
Date: Thu, 14 Jan 2021 17:10:21 +0200
Subject: [PATCH v2 net-next 09/21] nvme-tcp: Deal with netdevice DOWN events
In-Reply-To: <20210114151033.13020-1-borisp@mellanox.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
Message-ID: <20210114151033.13020-10-borisp@mellanox.com>

From: Or Gerlitz <ogerlitz at mellanox.com>

For ddp setup/teardown and resync, the offloading logic
uses HW resources at the NIC driver such as SQ and CQ.

These resources are destroyed when the netdevice does down
and hence we must stop using them before the NIC driver
destroys them.

Use netdevice notifier for that matter -- offloaded connections
are stopped before the stack continues to call the NIC driver
close ndo.

We use the existing recovery flow which has the advantage
of resuming the offload once the connection is re-set.

This also buys us proper handling for the UNREGISTER event
b/c our offloading starts in the UP state, and down is always
there between up to unregister.

Signed-off-by: Or Gerlitz <ogerlitz at mellanox.com>
Signed-off-by: Boris Pismenny <borisp at mellanox.com>
Signed-off-by: Ben Ben-Ishay <benishay at mellanox.com>
Signed-off-by: Yoray Zack <yorayz at mellanox.com>
---
 drivers/nvme/host/tcp.c | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 09d2e2e529cd..f85d04346156 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -145,6 +145,7 @@ struct nvme_tcp_ctrl {
 
 static LIST_HEAD(nvme_tcp_ctrl_list);
 static DEFINE_MUTEX(nvme_tcp_ctrl_mutex);
+static struct notifier_block nvme_tcp_netdevice_nb;
 static struct workqueue_struct *nvme_tcp_wq;
 static const struct blk_mq_ops nvme_tcp_mq_ops;
 static const struct blk_mq_ops nvme_tcp_admin_mq_ops;
@@ -2913,6 +2914,27 @@ static struct nvme_ctrl *nvme_tcp_create_ctrl(struct device *dev,
 	return ERR_PTR(ret);
 }
 
+static int nvme_tcp_netdev_event(struct notifier_block *this,
+				 unsigned long event, void *ptr)
+{
+	struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
+	struct nvme_tcp_ctrl *ctrl;
+
+	switch (event) {
+	case NETDEV_GOING_DOWN:
+		mutex_lock(&nvme_tcp_ctrl_mutex);
+		list_for_each_entry(ctrl, &nvme_tcp_ctrl_list, list) {
+			if (ndev != ctrl->offloading_netdev)
+				continue;
+			nvme_tcp_error_recovery(&ctrl->ctrl);
+		}
+		mutex_unlock(&nvme_tcp_ctrl_mutex);
+		flush_workqueue(nvme_reset_wq);
+		/* we assume that the going down part of error recovery is over */
+	}
+	return NOTIFY_DONE;
+}
+
 static struct nvmf_transport_ops nvme_tcp_transport = {
 	.name		= "tcp",
 	.module		= THIS_MODULE,
@@ -2927,13 +2949,26 @@ static struct nvmf_transport_ops nvme_tcp_transport = {
 
 static int __init nvme_tcp_init_module(void)
 {
+	int ret;
+
 	nvme_tcp_wq = alloc_workqueue("nvme_tcp_wq",
 			WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
 	if (!nvme_tcp_wq)
 		return -ENOMEM;
 
+	nvme_tcp_netdevice_nb.notifier_call = nvme_tcp_netdev_event;
+	ret = register_netdevice_notifier(&nvme_tcp_netdevice_nb);
+	if (ret) {
+		pr_err("failed to register netdev notifier\n");
+		goto out_err_reg_notifier;
+	}
+
 	nvmf_register_transport(&nvme_tcp_transport);
 	return 0;
+
+out_err_reg_notifier:
+	destroy_workqueue(nvme_tcp_wq);
+	return ret;
 }
 
 static void __exit nvme_tcp_cleanup_module(void)
@@ -2941,6 +2976,7 @@ static void __exit nvme_tcp_cleanup_module(void)
 	struct nvme_tcp_ctrl *ctrl;
 
 	nvmf_unregister_transport(&nvme_tcp_transport);
+	unregister_netdevice_notifier(&nvme_tcp_netdevice_nb);
 
 	mutex_lock(&nvme_tcp_ctrl_mutex);
 	list_for_each_entry(ctrl, &nvme_tcp_ctrl_list, list)
-- 
2.24.1



From borisp at mellanox.com  Thu Jan 14 10:10:22 2021
From: borisp at mellanox.com (Boris Pismenny)
Date: Thu, 14 Jan 2021 17:10:22 +0200
Subject: [PATCH v2 net-next 10/21] net/mlx5: Header file changes for nvme-tcp
 offload
In-Reply-To: <20210114151033.13020-1-borisp@mellanox.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
Message-ID: <20210114151033.13020-11-borisp@mellanox.com>

From: Ben Ben-ishay <benishay at nvidia.com>

Add the necessary infrastructure for NVMEoTCP offload:

- Add nvmeocp_en + nvmeotcp_crc_en bit to the TIR for identify NVMEoTCP offload flow
  And tag_buffer_id that will be used by the connected nvmeotcp_queues
- Add new CQE field that will be used to pass scattered data information to SW
- Add new capability to HCA_CAP that represnts the NVMEoTCP offload ability

Signed-off-by: Ben Ben-ishay <benishay at nvidia.com>
Signed-off-by: Boris Pismenny <borisp at mellanox.com>
Signed-off-by: Or Gerlitz <ogerlitz at mellanox.com>
Signed-off-by: Yoray Zack <yorayz at mellanox.com>
---
 include/linux/mlx5/device.h   |   8 +++
 include/linux/mlx5/mlx5_ifc.h | 101 +++++++++++++++++++++++++++++++++-
 include/linux/mlx5/qp.h       |   1 +
 3 files changed, 107 insertions(+), 3 deletions(-)

diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h
index 00057eae89ab..4433ff213d32 100644
--- a/include/linux/mlx5/device.h
+++ b/include/linux/mlx5/device.h
@@ -263,6 +263,7 @@ enum {
 enum {
 	MLX5_MKEY_MASK_LEN		= 1ull << 0,
 	MLX5_MKEY_MASK_PAGE_SIZE	= 1ull << 1,
+	MLX5_MKEY_MASK_XLT_OCT_SIZE     = 1ull << 2,
 	MLX5_MKEY_MASK_START_ADDR	= 1ull << 6,
 	MLX5_MKEY_MASK_PD		= 1ull << 7,
 	MLX5_MKEY_MASK_EN_RINVAL	= 1ull << 8,
@@ -1171,6 +1172,7 @@ enum mlx5_cap_type {
 	MLX5_CAP_VDPA_EMULATION = 0x13,
 	MLX5_CAP_DEV_EVENT = 0x14,
 	MLX5_CAP_IPSEC,
+	MLX5_CAP_DEV_NVMEOTCP = 0x19,
 	/* NUM OF CAP Types */
 	MLX5_CAP_NUM
 };
@@ -1391,6 +1393,12 @@ enum mlx5_qcam_feature_groups {
 #define MLX5_CAP_IPSEC(mdev, cap)\
 	MLX5_GET(ipsec_cap, (mdev)->caps.hca_cur[MLX5_CAP_IPSEC], cap)
 
+#define MLX5_CAP_DEV_NVMEOTCP(mdev, cap)\
+	MLX5_GET(nvmeotcp_cap, mdev->caps.hca_cur[MLX5_CAP_DEV_NVMEOTCP], cap)
+
+#define MLX5_CAP64_NVMEOTCP(mdev, cap)\
+	MLX5_GET64(nvmeotcp_cap, mdev->caps.hca_cur[MLX5_CAP_DEV_NVMEOTCP], cap)
+
 enum {
 	MLX5_CMD_STAT_OK			= 0x0,
 	MLX5_CMD_STAT_INT_ERR			= 0x1,
diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h
index ec0d01e26b3e..923f8961d50d 100644
--- a/include/linux/mlx5/mlx5_ifc.h
+++ b/include/linux/mlx5/mlx5_ifc.h
@@ -1271,7 +1271,9 @@ struct mlx5_ifc_cmd_hca_cap_bits {
 	u8         log_max_srq_sz[0x8];
 	u8         log_max_qp_sz[0x8];
 	u8         event_cap[0x1];
-	u8         reserved_at_91[0x7];
+	u8         reserved_at_91[0x5];
+	u8         nvmeotcp[0x1];
+	u8         reserved_at_97[0x1];
 	u8         prio_tag_required[0x1];
 	u8         reserved_at_99[0x2];
 	u8         log_max_qp[0x5];
@@ -3020,6 +3022,21 @@ struct mlx5_ifc_roce_addr_layout_bits {
 	u8         reserved_at_e0[0x20];
 };
 
+struct mlx5_ifc_nvmeotcp_cap_bits {
+	u8    zerocopy[0x1];
+	u8    crc_rx[0x1];
+	u8    crc_tx[0x1];
+	u8    reserved_at_3[0x15];
+	u8    version[0x8];
+
+	u8    reserved_at_20[0x13];
+	u8    log_max_nvmeotcp_tag_buffer_table[0x5];
+	u8    reserved_at_38[0x3];
+	u8    log_max_nvmeotcp_tag_buffer_size[0x5];
+
+	u8    reserved_at_40[0x7c0];
+};
+
 union mlx5_ifc_hca_cap_union_bits {
 	struct mlx5_ifc_cmd_hca_cap_bits cmd_hca_cap;
 	struct mlx5_ifc_odp_cap_bits odp_cap;
@@ -3036,6 +3053,7 @@ union mlx5_ifc_hca_cap_union_bits {
 	struct mlx5_ifc_tls_cap_bits tls_cap;
 	struct mlx5_ifc_device_mem_cap_bits device_mem_cap;
 	struct mlx5_ifc_virtio_emulation_cap_bits virtio_emulation_cap;
+	struct mlx5_ifc_nvmeotcp_cap_bits nvmeotcp_cap;
 	u8         reserved_at_0[0x8000];
 };
 
@@ -3230,7 +3248,9 @@ struct mlx5_ifc_tirc_bits {
 
 	u8         disp_type[0x4];
 	u8         tls_en[0x1];
-	u8         reserved_at_25[0x1b];
+	u8         nvmeotcp_zero_copy_en[0x1];
+	u8         nvmeotcp_crc_en[0x1];
+	u8         reserved_at_27[0x19];
 
 	u8         reserved_at_40[0x40];
 
@@ -3261,7 +3281,8 @@ struct mlx5_ifc_tirc_bits {
 
 	struct mlx5_ifc_rx_hash_field_select_bits rx_hash_field_selector_inner;
 
-	u8         reserved_at_2c0[0x4c0];
+	u8         nvmeotcp_tag_buffer_table_id[0x20];
+	u8         reserved_at_2e0[0x4a0];
 };
 
 enum {
@@ -10716,12 +10737,14 @@ enum {
 	MLX5_HCA_CAP_GENERAL_OBJECT_TYPES_ENCRYPTION_KEY = BIT_ULL(0xc),
 	MLX5_HCA_CAP_GENERAL_OBJECT_TYPES_IPSEC = BIT_ULL(0x13),
 	MLX5_HCA_CAP_GENERAL_OBJECT_TYPES_SAMPLER = BIT_ULL(0x20),
+	MLX5_HCA_CAP_GENERAL_OBJECT_TYPES_NVMEOTCP_TAG_BUFFER_TABLE = BIT_ULL(0x21),
 };
 
 enum {
 	MLX5_GENERAL_OBJECT_TYPES_ENCRYPTION_KEY = 0xc,
 	MLX5_GENERAL_OBJECT_TYPES_IPSEC = 0x13,
 	MLX5_GENERAL_OBJECT_TYPES_SAMPLER = 0x20,
+	MLX5_GENERAL_OBJECT_TYPES_NVMEOTCP_TAG_BUFFER_TABLE = 0x21
 };
 
 enum {
@@ -10823,6 +10846,20 @@ struct mlx5_ifc_create_sampler_obj_in_bits {
 	struct mlx5_ifc_sampler_obj_bits sampler_object;
 };
 
+struct mlx5_ifc_nvmeotcp_tag_buf_table_obj_bits {
+	u8    modify_field_select[0x40];
+
+	u8    reserved_at_20[0x20];
+
+	u8    reserved_at_40[0x1b];
+	u8    log_tag_buffer_table_size[0x5];
+};
+
+struct mlx5_ifc_create_nvmeotcp_tag_buf_table_in_bits {
+	struct mlx5_ifc_general_obj_in_cmd_hdr_bits general_obj_in_cmd_hdr;
+	struct mlx5_ifc_nvmeotcp_tag_buf_table_obj_bits nvmeotcp_tag_buf_table_obj;
+};
+
 enum {
 	MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_KEY_SIZE_128 = 0x0,
 	MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_KEY_SIZE_256 = 0x1,
@@ -10833,6 +10870,18 @@ enum {
 	MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_TYPE_IPSEC = 0x2,
 };
 
+enum {
+	MLX5_TRANSPORT_STATIC_PARAMS_ACC_TYPE_XTS               = 0x0,
+	MLX5_TRANSPORT_STATIC_PARAMS_ACC_TYPE_TLS               = 0x1,
+	MLX5_TRANSPORT_STATIC_PARAMS_ACC_TYPE_NVMETCP           = 0x2,
+	MLX5_TRANSPORT_STATIC_PARAMS_ACC_TYPE_NVMETCP_WITH_TLS  = 0x3,
+};
+
+enum {
+	MLX5_TRANSPORT_STATIC_PARAMS_TI_INITIATOR  = 0x0,
+	MLX5_TRANSPORT_STATIC_PARAMS_TI_TARGET     = 0x1,
+};
+
 struct mlx5_ifc_tls_static_params_bits {
 	u8         const_2[0x2];
 	u8         tls_version[0x4];
@@ -10873,4 +10922,50 @@ enum {
 	MLX5_MTT_PERM_RW	= MLX5_MTT_PERM_READ | MLX5_MTT_PERM_WRITE,
 };
 
+struct mlx5_ifc_nvmeotcp_progress_params_bits {
+	u8    next_pdu_tcp_sn[0x20];
+
+	u8    hw_resync_tcp_sn[0x20];
+
+	u8    pdu_tracker_state[0x2];
+	u8    offloading_state[0x2];
+	u8    reserved_at_64[0xc];
+	u8    cccid_ttag[0x10];
+};
+
+struct mlx5_ifc_transport_static_params_bits {
+	u8    const_2[0x2];
+	u8    tls_version[0x4];
+	u8    const_1[0x2];
+	u8    reserved_at_8[0x14];
+	u8    acc_type[0x4];
+
+	u8    reserved_at_20[0x20];
+
+	u8    initial_record_number[0x40];
+
+	u8    resync_tcp_sn[0x20];
+
+	u8    gcm_iv[0x20];
+
+	u8    implicit_iv[0x40];
+
+	u8    reserved_at_100[0x8];
+	u8    dek_index[0x18];
+
+	u8    reserved_at_120[0x14];
+	u8    const1[0x1];
+	u8    ti[0x1];
+	u8    zero_copy_en[0x1];
+	u8    ddgst_offload_en[0x1];
+	u8    hdgst_offload_en[0x1];
+	u8    ddgst_en[0x1];
+	u8    hddgst_en[0x1];
+	u8    pda[0x5];
+
+	u8    nvme_resync_tcp_sn[0x20];
+
+	u8    reserved_at_160[0xa0];
+};
+
 #endif /* MLX5_IFC_H */
diff --git a/include/linux/mlx5/qp.h b/include/linux/mlx5/qp.h
index d75ef8aa8fac..5fa8b82c9edb 100644
--- a/include/linux/mlx5/qp.h
+++ b/include/linux/mlx5/qp.h
@@ -220,6 +220,7 @@ struct mlx5_wqe_ctrl_seg {
 #define MLX5_WQE_CTRL_OPCODE_MASK 0xff
 #define MLX5_WQE_CTRL_WQE_INDEX_MASK 0x00ffff00
 #define MLX5_WQE_CTRL_WQE_INDEX_SHIFT 8
+#define MLX5_WQE_CTRL_TIR_TIS_INDEX_SHIFT 8
 
 enum {
 	MLX5_ETH_WQE_L3_INNER_CSUM      = 1 << 4,
-- 
2.24.1



From borisp at mellanox.com  Thu Jan 14 10:10:14 2021
From: borisp at mellanox.com (Boris Pismenny)
Date: Thu, 14 Jan 2021 17:10:14 +0200
Subject: [PATCH v2 net-next 02/21] net: Introduce direct data placement tcp
 offload
In-Reply-To: <20210114151033.13020-1-borisp@mellanox.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
Message-ID: <20210114151033.13020-3-borisp@mellanox.com>

This commit introduces direct data placement offload for TCP.
This capability is accompanied by new net_device operations that
configure hardware contexts. There is a context per socket, and a context per DDP
opreation. Additionally, a resynchronization routine is used to assist
hardware handle TCP OOO, and continue the offload.
Furthermore, we let the offloading driver advertise what is the max hw
sectors/segments.

Using this interface, the NIC hardware will scatter TCP payload directly
to the BIO pages according to the command_id.
To maintain the correctness of the network stack, the driver is expected
to construct SKBs that point to the BIO pages.

This, the SKB represents the data on the wire, while it is pointing
to data that is already placed in the destination buffer.
As a result, data from page frags should not be copied out to
the linear part.

As SKBs that use DDP are already very memory efficient, we modify
skb_condence to avoid copying data from fragments to the linear
part of SKBs that belong to a socket that uses DDP offload.

A follow-up patch will use this interface for DDP in NVMe-TCP.

Signed-off-by: Boris Pismenny <borisp at mellanox.com>
Signed-off-by: Ben Ben-Ishay <benishay at mellanox.com>
Signed-off-by: Or Gerlitz <ogerlitz at mellanox.com>
Signed-off-by: Yoray Zack <yorayz at mellanox.com>
---
 include/linux/netdev_features.h    |   2 +
 include/linux/netdevice.h          |   5 ++
 include/net/inet_connection_sock.h |   4 +
 include/net/tcp_ddp.h              | 136 +++++++++++++++++++++++++++++
 net/Kconfig                        |   9 ++
 net/core/skbuff.c                  |   9 +-
 net/ethtool/common.c               |   1 +
 7 files changed, 165 insertions(+), 1 deletion(-)
 create mode 100644 include/net/tcp_ddp.h

diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h
index 934de56644e7..fb35dcac03d2 100644
--- a/include/linux/netdev_features.h
+++ b/include/linux/netdev_features.h
@@ -84,6 +84,7 @@ enum {
 	NETIF_F_GRO_FRAGLIST_BIT,	/* Fraglist GRO */
 
 	NETIF_F_HW_MACSEC_BIT,		/* Offload MACsec operations */
+	NETIF_F_HW_TCP_DDP_BIT,		/* TCP direct data placement offload */
 
 	/*
 	 * Add your fresh new feature above and remember to update
@@ -157,6 +158,7 @@ enum {
 #define NETIF_F_GRO_FRAGLIST	__NETIF_F(GRO_FRAGLIST)
 #define NETIF_F_GSO_FRAGLIST	__NETIF_F(GSO_FRAGLIST)
 #define NETIF_F_HW_MACSEC	__NETIF_F(HW_MACSEC)
+#define NETIF_F_HW_TCP_DDP	__NETIF_F(HW_TCP_DDP)
 
 /* Finds the next feature with the highest number of the range of start till 0.
  */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 259be67644e3..3dd3cdf5dec3 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -941,6 +941,7 @@ struct dev_ifalias {
 
 struct devlink;
 struct tlsdev_ops;
+struct tcp_ddp_dev_ops;
 
 struct netdev_name_node {
 	struct hlist_node hlist;
@@ -1937,6 +1938,10 @@ struct net_device {
 	const struct tlsdev_ops *tlsdev_ops;
 #endif
 
+#ifdef CONFIG_TCP_DDP
+	const struct tcp_ddp_dev_ops *tcp_ddp_ops;
+#endif
+
 	const struct header_ops *header_ops;
 
 	unsigned int		flags;
diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h
index 7338b3865a2a..a08b85b53aa8 100644
--- a/include/net/inet_connection_sock.h
+++ b/include/net/inet_connection_sock.h
@@ -66,6 +66,8 @@ struct inet_connection_sock_af_ops {
  * @icsk_ulp_ops	   Pluggable ULP control hook
  * @icsk_ulp_data	   ULP private data
  * @icsk_clean_acked	   Clean acked data hook
+ * @icsk_ulp_ddp_ops	   Pluggable ULP direct data placement control hook
+ * @icsk_ulp_ddp_data	   ULP direct data placement private data
  * @icsk_listen_portaddr_node	hash to the portaddr listener hashtable
  * @icsk_ca_state:	   Congestion control state
  * @icsk_retransmits:	   Number of unrecovered [RTO] timeouts
@@ -94,6 +96,8 @@ struct inet_connection_sock {
 	const struct tcp_ulp_ops  *icsk_ulp_ops;
 	void __rcu		  *icsk_ulp_data;
 	void (*icsk_clean_acked)(struct sock *sk, u32 acked_seq);
+	const struct tcp_ddp_ulp_ops  *icsk_ulp_ddp_ops;
+	void __rcu		  *icsk_ulp_ddp_data;
 	struct hlist_node         icsk_listen_portaddr_node;
 	unsigned int		  (*icsk_sync_mss)(struct sock *sk, u32 pmtu);
 	__u8			  icsk_ca_state:5,
diff --git a/include/net/tcp_ddp.h b/include/net/tcp_ddp.h
new file mode 100644
index 000000000000..31e5b1a16d0f
--- /dev/null
+++ b/include/net/tcp_ddp.h
@@ -0,0 +1,136 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * tcp_ddp.h
+ *	Author:	Boris Pismenny <borisp at mellanox.com>
+ *	Copyright (C) 2021 Mellanox Technologies.
+ */
+#ifndef _TCP_DDP_H
+#define _TCP_DDP_H
+
+#include <linux/netdevice.h>
+#include <net/inet_connection_sock.h>
+#include <net/sock.h>
+
+/* limits returned by the offload driver, zero means don't care */
+struct tcp_ddp_limits {
+	int	 max_ddp_sgl_len;
+};
+
+enum tcp_ddp_type {
+	TCP_DDP_NVME = 1,
+};
+
+/**
+ * struct tcp_ddp_config - Generic tcp ddp configuration: tcp ddp IO queue
+ * config implementations must use this as the first member.
+ * Add new instances of tcp_ddp_config below (nvme-tcp, etc.).
+ */
+struct tcp_ddp_config {
+	enum tcp_ddp_type    type;
+	unsigned char        buf[];
+};
+
+/**
+ * struct nvme_tcp_ddp_config - nvme tcp ddp configuration for an IO queue
+ *
+ * @pfv:        pdu version (e.g., NVME_TCP_PFV_1_0)
+ * @cpda:       controller pdu data alignmend (dwords, 0's based)
+ * @dgst:       digest types enabled.
+ *              The netdev will offload crc if ddp_crc is supported.
+ * @queue_size: number of nvme-tcp IO queue elements
+ * @queue_id:   queue identifier
+ * @cpu_io:     cpu core running the IO thread for this queue
+ */
+struct nvme_tcp_ddp_config {
+	struct tcp_ddp_config   cfg;
+
+	u16			pfv;
+	u8			cpda;
+	u8			dgst;
+	int			queue_size;
+	int			queue_id;
+	int			io_cpu;
+};
+
+/**
+ * struct tcp_ddp_io - tcp ddp configuration for an IO request.
+ *
+ * @command_id:  identifier on the wire associated with these buffers
+ * @nents:       number of entries in the sg_table
+ * @sg_table:    describing the buffers for this IO request
+ * @first_sgl:   first SGL in sg_table
+ */
+struct tcp_ddp_io {
+	u32			command_id;
+	int			nents;
+	struct sg_table		sg_table;
+	struct scatterlist	first_sgl[SG_CHUNK_SIZE];
+};
+
+/* struct tcp_ddp_dev_ops - operations used by an upper layer protocol to configure ddp offload
+ *
+ * @tcp_ddp_limits:    limit the number of scatter gather entries per IO.
+ *                     the device driver can use this to limit the resources allocated per queue.
+ * @tcp_ddp_sk_add:    add offload for the queue represennted by the socket+config pair.
+ *                     this function is used to configure either copy, crc or both offloads.
+ * @tcp_ddp_sk_del:    remove offload from the socket, and release any device related resources.
+ * @tcp_ddp_setup:     request copy offload for buffers associated with a command_id in tcp_ddp_io.
+ * @tcp_ddp_teardown:  release offload resources association between buffers and command_id in
+ *                     tcp_ddp_io.
+ * @tcp_ddp_resync:    respond to the driver's resync_request. Called only if resync is successful.
+ */
+struct tcp_ddp_dev_ops {
+	int (*tcp_ddp_limits)(struct net_device *netdev,
+			      struct tcp_ddp_limits *limits);
+	int (*tcp_ddp_sk_add)(struct net_device *netdev,
+			      struct sock *sk,
+			      struct tcp_ddp_config *config);
+	void (*tcp_ddp_sk_del)(struct net_device *netdev,
+			       struct sock *sk);
+	int (*tcp_ddp_setup)(struct net_device *netdev,
+			     struct sock *sk,
+			     struct tcp_ddp_io *io);
+	int (*tcp_ddp_teardown)(struct net_device *netdev,
+				struct sock *sk,
+				struct tcp_ddp_io *io,
+				void *ddp_ctx);
+	void (*tcp_ddp_resync)(struct net_device *netdev,
+			       struct sock *sk, u32 seq);
+};
+
+#define TCP_DDP_RESYNC_REQ BIT(0)
+
+/**
+ * struct tcp_ddp_ulp_ops - Interface to register uppper layer Direct Data Placement (DDP) TCP offload
+ */
+struct tcp_ddp_ulp_ops {
+	/* NIC requests ulp to indicate if @seq is the start of a message */
+	bool (*resync_request)(struct sock *sk, u32 seq, u32 flags);
+	/* NIC driver informs the ulp that ddp teardown is done - used for async completions*/
+	void (*ddp_teardown_done)(void *ddp_ctx);
+};
+
+/**
+ * struct tcp_ddp_ctx - Generic tcp ddp context: device driver per queue contexts must
+ * use this as the first member.
+ */
+struct tcp_ddp_ctx {
+	enum tcp_ddp_type    type;
+	unsigned char        buf[];
+};
+
+static inline struct tcp_ddp_ctx *tcp_ddp_get_ctx(const struct sock *sk)
+{
+	struct inet_connection_sock *icsk = inet_csk(sk);
+
+	return (__force struct tcp_ddp_ctx *)icsk->icsk_ulp_ddp_data;
+}
+
+static inline void tcp_ddp_set_ctx(struct sock *sk, void *ctx)
+{
+	struct inet_connection_sock *icsk = inet_csk(sk);
+
+	rcu_assign_pointer(icsk->icsk_ulp_ddp_data, ctx);
+}
+
+#endif //_TCP_DDP_H
diff --git a/net/Kconfig b/net/Kconfig
index f4c32d982af6..3876861cdc90 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -457,6 +457,15 @@ config ETHTOOL_NETLINK
 	  netlink. It provides better extensibility and some new features,
 	  e.g. notification messages.
 
+config TCP_DDP
+	bool "TCP direct data placement offload"
+	default n
+	help
+	  Direct Data Placement (DDP) offload for TCP enables ULP, such as
+	  NVMe-TCP/iSCSI, to request the NIC to place TCP payload data
+	  of a command response directly into kernel pages.
+
+
 endif   # if NET
 
 # Used by archs to tell that they support BPF JIT compiler plus which flavour.
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index f62cae3f75d8..791c1b6bc067 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -69,6 +69,7 @@
 #include <net/xfrm.h>
 #include <net/mpls.h>
 #include <net/mptcp.h>
+#include <net/tcp_ddp.h>
 
 #include <linux/uaccess.h>
 #include <trace/events/skb.h>
@@ -6140,9 +6141,15 @@ EXPORT_SYMBOL(pskb_extract);
  */
 void skb_condense(struct sk_buff *skb)
 {
+	bool is_ddp = false;
+
+#ifdef CONFIG_TCP_DDP
+	is_ddp = skb->sk && inet_csk(skb->sk) &&
+		 inet_csk(skb->sk)->icsk_ulp_ddp_data;
+#endif
 	if (skb->data_len) {
 		if (skb->data_len > skb->end - skb->tail ||
-		    skb_cloned(skb))
+		    skb_cloned(skb) || is_ddp)
 			return;
 
 		/* Nice, we can free page frag(s) right now */
diff --git a/net/ethtool/common.c b/net/ethtool/common.c
index 24036e3055a1..a2ff7a4a6bbf 100644
--- a/net/ethtool/common.c
+++ b/net/ethtool/common.c
@@ -68,6 +68,7 @@ const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] = {
 	[NETIF_F_HW_TLS_RX_BIT] =	 "tls-hw-rx-offload",
 	[NETIF_F_GRO_FRAGLIST_BIT] =	 "rx-gro-list",
 	[NETIF_F_HW_MACSEC_BIT] =	 "macsec-hw-offload",
+	[NETIF_F_HW_TCP_DDP_BIT] =	 "tcp-ddp-offload",
 };
 
 const char
-- 
2.24.1



From borisp at mellanox.com  Thu Jan 14 10:10:32 2021
From: borisp at mellanox.com (Boris Pismenny)
Date: Thu, 14 Jan 2021 17:10:32 +0200
Subject: [PATCH v2 net-next 20/21] net/mlx5e: NVMEoTCP statistics
In-Reply-To: <20210114151033.13020-1-borisp@mellanox.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
Message-ID: <20210114151033.13020-21-borisp@mellanox.com>

From: Ben Ben-Ishay <benishay at nvidia.com>

NVMEoTCP offload statistics includes both control and data path
statistic: counters for ndo, offloaded packets/bytes, dropped packets
and resync operation.

Signed-off-by: Boris Pismenny <borisp at mellanox.com>
Signed-off-by: Ben Ben-Ishay <benishay at nvidia.com>
Signed-off-by: Or Gerlitz <ogerlitz at mellanox.com>
Signed-off-by: Yoray Zack <yorayz at mellanox.com>
---
 .../mellanox/mlx5/core/en_accel/nvmeotcp.c    | 23 +++++++++++-
 .../mlx5/core/en_accel/nvmeotcp_rxtx.c        | 16 ++++++++
 .../ethernet/mellanox/mlx5/core/en_stats.c    | 37 +++++++++++++++++++
 .../ethernet/mellanox/mlx5/core/en_stats.h    | 24 ++++++++++++
 4 files changed, 98 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.c
index c2967cb4cb6a..80cd32942d8d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.c
@@ -656,6 +656,11 @@ mlx5e_nvmeotcp_queue_init(struct net_device *netdev,
 	struct mlx5_core_dev *mdev = priv->mdev;
 	struct mlx5e_nvmeotcp_queue *queue;
 	int max_wqe_sz_cap, queue_id, err;
+	struct mlx5e_rq_stats *stats;
+	u32 channel_ix;
+
+	channel_ix = mlx5e_get_channel_ix_from_io_cpu(priv, config->io_cpu);
+	stats = &priv->channel_stats[channel_ix].rq;
 
 	if (tconfig->type != TCP_DDP_NVME) {
 		err = -EOPNOTSUPP;
@@ -683,8 +688,7 @@ mlx5e_nvmeotcp_queue_init(struct net_device *netdev,
 	queue->id = queue_id;
 	queue->dgst = config->dgst;
 	queue->pda = config->cpda;
-	queue->channel_ix = mlx5e_get_channel_ix_from_io_cpu(priv,
-							     config->io_cpu);
+	queue->channel_ix = channel_ix;
 	queue->size = config->queue_size;
 	max_wqe_sz_cap  = min_t(int, MAX_DS_VALUE * MLX5_SEND_WQE_DS,
 				MLX5_CAP_GEN(mdev, max_wqe_sz_sq) << OCTWORD_SHIFT);
@@ -704,6 +708,7 @@ mlx5e_nvmeotcp_queue_init(struct net_device *netdev,
 	if (err)
 		goto destroy_rx;
 
+	stats->nvmeotcp_queue_init++;
 	write_lock_bh(&sk->sk_callback_lock);
 	tcp_ddp_set_ctx(sk, queue);
 	write_unlock_bh(&sk->sk_callback_lock);
@@ -718,6 +723,7 @@ mlx5e_nvmeotcp_queue_init(struct net_device *netdev,
 free_queue:
 	kfree(queue);
 out:
+	stats->nvmeotcp_queue_init_fail++;
 	return err;
 }
 
@@ -728,11 +734,15 @@ mlx5e_nvmeotcp_queue_teardown(struct net_device *netdev,
 	struct mlx5e_priv *priv = netdev_priv(netdev);
 	struct mlx5_core_dev *mdev = priv->mdev;
 	struct mlx5e_nvmeotcp_queue *queue;
+	struct mlx5e_rq_stats *stats;
 
 	queue = container_of(tcp_ddp_get_ctx(sk), struct mlx5e_nvmeotcp_queue, tcp_ddp_ctx);
 
 	napi_synchronize(&priv->channels.c[queue->channel_ix]->napi);
 
+	stats = &priv->channel_stats[queue->channel_ix].rq;
+	stats->nvmeotcp_queue_teardown++;
+
 	WARN_ON(refcount_read(&queue->ref_count) != 1);
 	if (queue->zerocopy | queue->crc_rx)
 		mlx5e_nvmeotcp_destroy_rx(queue, mdev, queue->zerocopy);
@@ -754,6 +764,7 @@ mlx5e_nvmeotcp_ddp_setup(struct net_device *netdev,
 	struct mlx5e_priv *priv = netdev_priv(netdev);
 	struct scatterlist *sg = ddp->sg_table.sgl;
 	struct mlx5e_nvmeotcp_queue *queue;
+	struct mlx5e_rq_stats *stats;
 	struct mlx5_core_dev *mdev;
 	int i, size = 0, count = 0;
 
@@ -775,6 +786,11 @@ mlx5e_nvmeotcp_ddp_setup(struct net_device *netdev,
 	queue->ccid_table[ddp->command_id].ccid_gen++;
 	queue->ccid_table[ddp->command_id].sgl_length = count;
 
+	stats = &priv->channel_stats[queue->channel_ix].rq;
+	stats->nvmeotcp_ddp_setup++;
+	if (unlikely(mlx5e_nvmeotcp_post_klm_wqe(queue, KLM_UMR, ddp->command_id, count)))
+		stats->nvmeotcp_ddp_setup_fail++;
+
 	return 0;
 }
 
@@ -815,6 +831,7 @@ mlx5e_nvmeotcp_ddp_teardown(struct net_device *netdev,
 	struct mlx5e_nvmeotcp_queue *queue;
 	struct mlx5e_priv *priv = netdev_priv(netdev);
 	struct nvmeotcp_queue_entry *q_entry;
+	struct mlx5e_rq_stats *stats;
 
 	queue = container_of(tcp_ddp_get_ctx(sk), struct mlx5e_nvmeotcp_queue, tcp_ddp_ctx);
 	q_entry  = &queue->ccid_table[ddp->command_id];
@@ -824,6 +841,8 @@ mlx5e_nvmeotcp_ddp_teardown(struct net_device *netdev,
 	q_entry->queue = queue;
 
 	mlx5e_nvmeotcp_post_klm_wqe(queue, KLM_UMR, ddp->command_id, 0);
+	stats = &priv->channel_stats[queue->channel_ix].rq;
+	stats->nvmeotcp_ddp_teardown++;
 
 	return 0;
 }
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp_rxtx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp_rxtx.c
index f446b5d56d64..e1558dfc0f3d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp_rxtx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp_rxtx.c
@@ -10,12 +10,16 @@ static void nvmeotcp_update_resync(struct mlx5e_nvmeotcp_queue *queue,
 				   struct mlx5e_cqe128 *cqe128)
 {
 	const struct tcp_ddp_ulp_ops *ulp_ops;
+	struct mlx5e_rq_stats *stats;
 	u32 seq;
 
 	seq = be32_to_cpu(cqe128->resync_tcp_sn);
 	ulp_ops = inet_csk(queue->sk)->icsk_ulp_ddp_ops;
 	if (ulp_ops && ulp_ops->resync_request)
 		ulp_ops->resync_request(queue->sk, seq, TCP_DDP_RESYNC_REQ);
+
+	stats = queue->priv->channels.c[queue->channel_ix]->rq.stats;
+	stats->nvmeotcp_resync++;
 }
 
 static void mlx5e_nvmeotcp_advance_sgl_iter(struct mlx5e_nvmeotcp_queue *queue)
@@ -50,10 +54,13 @@ mlx5_nvmeotcp_add_tail_nonlinear(struct mlx5e_nvmeotcp_queue *queue,
 				 int org_nr_frags, int frag_index)
 {
 	struct mlx5e_priv *priv = queue->priv;
+	struct mlx5e_rq_stats *stats;
 
 	while (org_nr_frags != frag_index) {
 		if (skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS) {
 			dev_kfree_skb_any(skb);
+			stats = priv->channels.c[queue->channel_ix]->rq.stats;
+			stats->nvmeotcp_drop++;
 			return NULL;
 		}
 		skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
@@ -72,9 +79,12 @@ mlx5_nvmeotcp_add_tail(struct mlx5e_nvmeotcp_queue *queue, struct sk_buff *skb,
 		       int offset, int len)
 {
 	struct mlx5e_priv *priv = queue->priv;
+	struct mlx5e_rq_stats *stats;
 
 	if (skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS) {
 		dev_kfree_skb_any(skb);
+		stats = priv->channels.c[queue->channel_ix]->rq.stats;
+		stats->nvmeotcp_drop++;
 		return NULL;
 	}
 	skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
@@ -135,6 +145,7 @@ mlx5e_nvmeotcp_handle_rx_skb(struct net_device *netdev, struct sk_buff *skb,
 	skb_frag_t org_frags[MAX_SKB_FRAGS];
 	struct mlx5e_nvmeotcp_queue *queue;
 	struct nvmeotcp_queue_entry *nqe;
+	struct mlx5e_rq_stats *stats;
 	int org_nr_frags, frag_index;
 	struct mlx5e_cqe128 *cqe128;
 	u32 queue_id;
@@ -167,6 +178,8 @@ mlx5e_nvmeotcp_handle_rx_skb(struct net_device *netdev, struct sk_buff *skb,
 		return skb;
 	}
 
+	stats = priv->channels.c[queue->channel_ix]->rq.stats;
+
 	/* cc ddp from cqe */
 	ccid = be16_to_cpu(cqe128->ccid);
 	ccoff = be32_to_cpu(cqe128->ccoff);
@@ -209,6 +222,7 @@ mlx5e_nvmeotcp_handle_rx_skb(struct net_device *netdev, struct sk_buff *skb,
 	while (to_copy < cclen) {
 		if (skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS) {
 			dev_kfree_skb_any(skb);
+			stats->nvmeotcp_drop++;
 			mlx5e_nvmeotcp_put_queue(queue);
 			return NULL;
 		}
@@ -238,6 +252,8 @@ mlx5e_nvmeotcp_handle_rx_skb(struct net_device *netdev, struct sk_buff *skb,
 							       frag_index);
 	}
 
+	stats->nvmeotcp_offload_packets++;
+	stats->nvmeotcp_offload_bytes += cclen;
 	mlx5e_nvmeotcp_put_queue(queue);
 	return skb;
 }
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
index 2cf2042b37c7..ca7d2cb5099f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
@@ -34,6 +34,7 @@
 #include "en.h"
 #include "en_accel/tls.h"
 #include "en_accel/en_accel.h"
+#include "en_accel/nvmeotcp.h"
 
 static unsigned int stats_grps_num(struct mlx5e_priv *priv)
 {
@@ -189,6 +190,18 @@ static const struct counter_desc sw_stats_desc[] = {
 	{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_tls_resync_res_ok) },
 	{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_tls_resync_res_skip) },
 	{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_tls_err) },
+#endif
+#ifdef CONFIG_MLX5_EN_NVMEOTCP
+	{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_nvmeotcp_queue_init) },
+	{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_nvmeotcp_queue_init_fail) },
+	{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_nvmeotcp_queue_teardown) },
+	{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_nvmeotcp_ddp_setup) },
+	{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_nvmeotcp_ddp_setup_fail) },
+	{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_nvmeotcp_ddp_teardown) },
+	{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_nvmeotcp_drop) },
+	{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_nvmeotcp_resync) },
+	{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_nvmeotcp_offload_packets) },
+	{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_nvmeotcp_offload_bytes) },
 #endif
 	{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, ch_events) },
 	{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, ch_poll) },
@@ -352,6 +365,18 @@ static void mlx5e_stats_grp_sw_update_stats_rq_stats(struct mlx5e_sw_stats *s,
 	s->rx_tls_resync_res_skip     += rq_stats->tls_resync_res_skip;
 	s->rx_tls_err                 += rq_stats->tls_err;
 #endif
+#ifdef CONFIG_MLX5_EN_NVMEOTCP
+	s->rx_nvmeotcp_queue_init      += rq_stats->nvmeotcp_queue_init;
+	s->rx_nvmeotcp_queue_init_fail += rq_stats->nvmeotcp_queue_init_fail;
+	s->rx_nvmeotcp_queue_teardown  += rq_stats->nvmeotcp_queue_teardown;
+	s->rx_nvmeotcp_ddp_setup       += rq_stats->nvmeotcp_ddp_setup;
+	s->rx_nvmeotcp_ddp_setup_fail  += rq_stats->nvmeotcp_ddp_setup_fail;
+	s->rx_nvmeotcp_ddp_teardown    += rq_stats->nvmeotcp_ddp_teardown;
+	s->rx_nvmeotcp_drop            += rq_stats->nvmeotcp_drop;
+	s->rx_nvmeotcp_resync          += rq_stats->nvmeotcp_resync;
+	s->rx_nvmeotcp_offload_packets += rq_stats->nvmeotcp_offload_packets;
+	s->rx_nvmeotcp_offload_bytes   += rq_stats->nvmeotcp_offload_bytes;
+#endif
 }
 
 static void mlx5e_stats_grp_sw_update_stats_ch_stats(struct mlx5e_sw_stats *s,
@@ -1612,6 +1637,18 @@ static const struct counter_desc rq_stats_desc[] = {
 	{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, tls_resync_res_skip) },
 	{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, tls_err) },
 #endif
+#ifdef CONFIG_MLX5_EN_NVMEOTCP
+	{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, nvmeotcp_queue_init) },
+	{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, nvmeotcp_queue_init_fail) },
+	{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, nvmeotcp_queue_teardown) },
+	{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, nvmeotcp_ddp_setup) },
+	{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, nvmeotcp_ddp_setup_fail) },
+	{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, nvmeotcp_ddp_teardown) },
+	{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, nvmeotcp_drop) },
+	{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, nvmeotcp_resync) },
+	{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, nvmeotcp_offload_packets) },
+	{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, nvmeotcp_offload_bytes) },
+#endif
 };
 
 static const struct counter_desc sq_stats_desc[] = {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
index e41fc11f2ce7..a5cf8ec4295b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
@@ -179,6 +179,18 @@ struct mlx5e_sw_stats {
 	u64 rx_congst_umr;
 	u64 rx_arfs_err;
 	u64 rx_recover;
+#ifdef CONFIG_MLX5_EN_NVMEOTCP
+	u64 rx_nvmeotcp_queue_init;
+	u64 rx_nvmeotcp_queue_init_fail;
+	u64 rx_nvmeotcp_queue_teardown;
+	u64 rx_nvmeotcp_ddp_setup;
+	u64 rx_nvmeotcp_ddp_setup_fail;
+	u64 rx_nvmeotcp_ddp_teardown;
+	u64 rx_nvmeotcp_drop;
+	u64 rx_nvmeotcp_resync;
+	u64 rx_nvmeotcp_offload_packets;
+	u64 rx_nvmeotcp_offload_bytes;
+#endif
 	u64 ch_events;
 	u64 ch_poll;
 	u64 ch_arm;
@@ -342,6 +354,18 @@ struct mlx5e_rq_stats {
 	u64 tls_resync_res_skip;
 	u64 tls_err;
 #endif
+#ifdef CONFIG_MLX5_EN_NVMEOTCP
+	u64 nvmeotcp_queue_init;
+	u64 nvmeotcp_queue_init_fail;
+	u64 nvmeotcp_queue_teardown;
+	u64 nvmeotcp_ddp_setup;
+	u64 nvmeotcp_ddp_setup_fail;
+	u64 nvmeotcp_ddp_teardown;
+	u64 nvmeotcp_drop;
+	u64 nvmeotcp_resync;
+	u64 nvmeotcp_offload_packets;
+	u64 nvmeotcp_offload_bytes;
+#endif
 };
 
 struct mlx5e_sq_stats {
-- 
2.24.1



From borisp at mellanox.com  Thu Jan 14 10:10:30 2021
From: borisp at mellanox.com (Boris Pismenny)
Date: Thu, 14 Jan 2021 17:10:30 +0200
Subject: [PATCH v2 net-next 18/21] net/mlx5e: NVMEoTCP ddp setup and resync
In-Reply-To: <20210114151033.13020-1-borisp@mellanox.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
Message-ID: <20210114151033.13020-19-borisp@mellanox.com>

From: Ben Ben-Ishay <benishay at nvidia.com>

NVMEoTCP offload uses buffer registration for every NVME request to perform direct data placement,
The registration is done via KLM UMR WQE's.
The driver resync handler advertise the software resync response via static params WQE.

Signed-off-by: Boris Pismenny <borisp at mellanox.com>
Signed-off-by: Ben Ben-Ishay <benishay at nvidia.com>
Signed-off-by: Or Gerlitz <ogerlitz at mellanox.com>
Signed-off-by: Yoray Zack <yorayz at mellanox.com>
---
 .../mellanox/mlx5/core/en_accel/nvmeotcp.c    | 33 +++++++++++++++++--
 1 file changed, 31 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.c
index 22fa1e9f3e7a..c2967cb4cb6a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp.c
@@ -751,6 +751,30 @@ mlx5e_nvmeotcp_ddp_setup(struct net_device *netdev,
 			 struct sock *sk,
 			 struct tcp_ddp_io *ddp)
 {
+	struct mlx5e_priv *priv = netdev_priv(netdev);
+	struct scatterlist *sg = ddp->sg_table.sgl;
+	struct mlx5e_nvmeotcp_queue *queue;
+	struct mlx5_core_dev *mdev;
+	int i, size = 0, count = 0;
+
+	queue = container_of(tcp_ddp_get_ctx(sk), struct mlx5e_nvmeotcp_queue, tcp_ddp_ctx);
+
+	mdev = queue->priv->mdev;
+	count = dma_map_sg(mdev->device, ddp->sg_table.sgl, ddp->nents,
+			   DMA_FROM_DEVICE);
+
+	if (WARN_ON(count > mlx5e_get_max_sgl(mdev)))
+		return -ENOSPC;
+
+	for (i = 0; i < count; i++)
+		size += sg[i].length;
+
+	queue->ccid_table[ddp->command_id].size = size;
+	queue->ccid_table[ddp->command_id].ddp = ddp;
+	queue->ccid_table[ddp->command_id].sgl = sg;
+	queue->ccid_table[ddp->command_id].ccid_gen++;
+	queue->ccid_table[ddp->command_id].sgl_length = count;
+
 	return 0;
 }
 
@@ -788,11 +812,11 @@ mlx5e_nvmeotcp_ddp_teardown(struct net_device *netdev,
 			    struct tcp_ddp_io *ddp,
 			    void *ddp_ctx)
 {
-	struct mlx5e_nvmeotcp_queue *queue =
-		(struct mlx5e_nvmeotcp_queue *)tcp_ddp_get_ctx(sk);
+	struct mlx5e_nvmeotcp_queue *queue;
 	struct mlx5e_priv *priv = netdev_priv(netdev);
 	struct nvmeotcp_queue_entry *q_entry;
 
+	queue = container_of(tcp_ddp_get_ctx(sk), struct mlx5e_nvmeotcp_queue, tcp_ddp_ctx);
 	q_entry  = &queue->ccid_table[ddp->command_id];
 	WARN_ON(q_entry->sgl_length == 0);
 
@@ -808,6 +832,11 @@ static void
 mlx5e_nvmeotcp_dev_resync(struct net_device *netdev,
 			  struct sock *sk, u32 seq)
 {
+	struct mlx5e_nvmeotcp_queue *queue =
+		container_of(tcp_ddp_get_ctx(sk), struct mlx5e_nvmeotcp_queue, tcp_ddp_ctx);
+
+	queue->after_resync_cqe = 1;
+	mlx5e_nvmeotcp_rx_post_static_params_wqe(queue, seq);
 }
 
 static const struct tcp_ddp_dev_ops mlx5e_nvmeotcp_ops = {
-- 
2.24.1



From borisp at mellanox.com  Thu Jan 14 10:10:31 2021
From: borisp at mellanox.com (Boris Pismenny)
Date: Thu, 14 Jan 2021 17:10:31 +0200
Subject: [PATCH v2 net-next 19/21] net/mlx5e: NVMEoTCP,
 data-path for DDP offload
In-Reply-To: <20210114151033.13020-1-borisp@mellanox.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
Message-ID: <20210114151033.13020-20-borisp@mellanox.com>

From: Ben Ben-Ishay <benishay at nvidia.com>

NVMEoTCP direct data placement constructs an SKB from each CQE, while
pointing at NVME buffers.

This enables the offload, as the NVMe-TCP layer will skip the copy when
src == dst.

Signed-off-by: Boris Pismenny <borisp at mellanox.com>
Signed-off-by: Ben Ben-Ishay <benishay at nvidia.com>
Signed-off-by: Or Gerlitz <ogerlitz at mellanox.com>
Signed-off-by: Yoray Zack <yorayz at mellanox.com>
---
 .../net/ethernet/mellanox/mlx5/core/Makefile  |   2 +-
 drivers/net/ethernet/mellanox/mlx5/core/en.h  |   1 +
 .../ethernet/mellanox/mlx5/core/en/xsk/rx.c   |   1 +
 .../ethernet/mellanox/mlx5/core/en/xsk/rx.h   |   1 +
 .../mlx5/core/en_accel/nvmeotcp_rxtx.c        | 243 ++++++++++++++++++
 .../mlx5/core/en_accel/nvmeotcp_rxtx.h        |  43 ++++
 .../net/ethernet/mellanox/mlx5/core/en_rx.c   |  41 ++-
 7 files changed, 325 insertions(+), 7 deletions(-)
 create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp_rxtx.c
 create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp_rxtx.h

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
index ada8cd22f8fb..fe22895ab1ee 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
@@ -97,4 +97,4 @@ mlx5_core-$(CONFIG_MLX5_SF) += sf/vhca_event.o sf/dev/dev.o sf/dev/driver.o
 #
 mlx5_core-$(CONFIG_MLX5_SF_MANAGER) += sf/cmd.o sf/hw_table.o sf/devlink.o
 
-mlx5_core-$(CONFIG_MLX5_EN_NVMEOTCP) += en_accel/fs_tcp.o en_accel/nvmeotcp.o
+mlx5_core-$(CONFIG_MLX5_EN_NVMEOTCP) += en_accel/fs_tcp.o en_accel/nvmeotcp.o en_accel/nvmeotcp_rxtx.o
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
index dc6ebcfffb1b..f41eb807d026 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@ -573,6 +573,7 @@ struct mlx5e_rq;
 typedef void (*mlx5e_fp_handle_rx_cqe)(struct mlx5e_rq*, struct mlx5_cqe64*);
 typedef struct sk_buff *
 (*mlx5e_fp_skb_from_cqe_mpwrq)(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
+			       struct mlx5_cqe64 *cqe,
 			       u16 cqe_bcnt, u32 head_offset, u32 page_idx);
 typedef struct sk_buff *
 (*mlx5e_fp_skb_from_cqe)(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.c
index 8e7b877d8a12..9a6fbd1b1c34 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.c
@@ -25,6 +25,7 @@ static struct sk_buff *mlx5e_xsk_construct_skb(struct mlx5e_rq *rq, void *data,
 
 struct sk_buff *mlx5e_xsk_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq,
 						    struct mlx5e_mpw_info *wi,
+						    struct mlx5_cqe64 *cqe,
 						    u16 cqe_bcnt,
 						    u32 head_offset,
 						    u32 page_idx)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.h b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.h
index 7f88ccf67fdd..112c5b3ec165 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.h
@@ -11,6 +11,7 @@
 
 struct sk_buff *mlx5e_xsk_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq,
 						    struct mlx5e_mpw_info *wi,
+						    struct mlx5_cqe64 *cqe,
 						    u16 cqe_bcnt,
 						    u32 head_offset,
 						    u32 page_idx);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp_rxtx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp_rxtx.c
new file mode 100644
index 000000000000..f446b5d56d64
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp_rxtx.c
@@ -0,0 +1,243 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/* Copyright (c) 2021 Mellanox Technologies. */
+
+#include "en_accel/nvmeotcp_rxtx.h"
+#include "en_accel/nvmeotcp.h"
+#include <linux/mlx5/mlx5_ifc.h>
+
+#define	MLX5E_TC_FLOW_ID_MASK  0x00ffffff
+static void nvmeotcp_update_resync(struct mlx5e_nvmeotcp_queue *queue,
+				   struct mlx5e_cqe128 *cqe128)
+{
+	const struct tcp_ddp_ulp_ops *ulp_ops;
+	u32 seq;
+
+	seq = be32_to_cpu(cqe128->resync_tcp_sn);
+	ulp_ops = inet_csk(queue->sk)->icsk_ulp_ddp_ops;
+	if (ulp_ops && ulp_ops->resync_request)
+		ulp_ops->resync_request(queue->sk, seq, TCP_DDP_RESYNC_REQ);
+}
+
+static void mlx5e_nvmeotcp_advance_sgl_iter(struct mlx5e_nvmeotcp_queue *queue)
+{
+	struct nvmeotcp_queue_entry *nqe = &queue->ccid_table[queue->ccid];
+
+	queue->ccoff += nqe->sgl[queue->ccsglidx].length;
+	queue->ccoff_inner = 0;
+	queue->ccsglidx++;
+}
+
+static inline void
+mlx5e_nvmeotcp_add_skb_frag(struct net_device *netdev, struct sk_buff *skb,
+			    struct mlx5e_nvmeotcp_queue *queue,
+			    struct nvmeotcp_queue_entry *nqe, u32 fragsz)
+{
+	dma_sync_single_for_cpu(&netdev->dev,
+				nqe->sgl[queue->ccsglidx].offset + queue->ccoff_inner,
+				fragsz, DMA_FROM_DEVICE);
+	page_ref_inc(compound_head(sg_page(&nqe->sgl[queue->ccsglidx])));
+	// XXX: consider reducing the truesize, as no new memory is consumed
+	skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
+			sg_page(&nqe->sgl[queue->ccsglidx]),
+			nqe->sgl[queue->ccsglidx].offset + queue->ccoff_inner,
+			fragsz,
+			fragsz);
+}
+
+static struct sk_buff*
+mlx5_nvmeotcp_add_tail_nonlinear(struct mlx5e_nvmeotcp_queue *queue,
+				 struct sk_buff *skb, skb_frag_t *org_frags,
+				 int org_nr_frags, int frag_index)
+{
+	struct mlx5e_priv *priv = queue->priv;
+
+	while (org_nr_frags != frag_index) {
+		if (skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS) {
+			dev_kfree_skb_any(skb);
+			return NULL;
+		}
+		skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
+				skb_frag_page(&org_frags[frag_index]),
+				skb_frag_off(&org_frags[frag_index]),
+				skb_frag_size(&org_frags[frag_index]),
+				skb_frag_size(&org_frags[frag_index]));
+		page_ref_inc(skb_frag_page(&org_frags[frag_index]));
+		frag_index++;
+	}
+	return skb;
+}
+
+static struct sk_buff*
+mlx5_nvmeotcp_add_tail(struct mlx5e_nvmeotcp_queue *queue, struct sk_buff *skb,
+		       int offset, int len)
+{
+	struct mlx5e_priv *priv = queue->priv;
+
+	if (skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS) {
+		dev_kfree_skb_any(skb);
+		return NULL;
+	}
+	skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
+			virt_to_page(skb->data),
+			offset,
+			len,
+			len);
+	page_ref_inc(virt_to_page(skb->data));
+	return skb;
+}
+
+static void mlx5_nvmeotcp_trim_nonlinear(struct sk_buff *skb,
+					 skb_frag_t *org_frags,
+					 int *frag_index,
+					 int remaining)
+{
+	unsigned int frag_size;
+	int nr_frags;
+
+	/* skip @remaining bytes in frags */
+	*frag_index = 0;
+	while (remaining) {
+		frag_size = skb_frag_size(&skb_shinfo(skb)->frags[*frag_index]);
+		if (frag_size > remaining) {
+			skb_frag_off_add(&skb_shinfo(skb)->frags[*frag_index],
+					 remaining);
+			skb_frag_size_sub(&skb_shinfo(skb)->frags[*frag_index],
+					  remaining);
+			remaining = 0;
+		} else {
+			remaining -= frag_size;
+			skb_frag_unref(skb, *frag_index);
+			*frag_index += 1;
+		}
+	}
+
+	/* save original frags for the tail and unref */
+	nr_frags = skb_shinfo(skb)->nr_frags;
+	memcpy(&org_frags[*frag_index], &skb_shinfo(skb)->frags[*frag_index],
+	       (nr_frags - *frag_index) * sizeof(skb_frag_t));
+	while (--nr_frags >= *frag_index)
+		skb_frag_unref(skb, nr_frags);
+
+	/* remove frags from skb */
+	skb_shinfo(skb)->nr_frags = 0;
+	skb->len -= skb->data_len;
+	skb->truesize -= skb->data_len;
+	skb->data_len = 0;
+}
+
+struct sk_buff*
+mlx5e_nvmeotcp_handle_rx_skb(struct net_device *netdev, struct sk_buff *skb,
+			     struct mlx5_cqe64 *cqe, u32 cqe_bcnt,
+			     bool linear)
+{
+	int ccoff, cclen, hlen, ccid, remaining, fragsz, to_copy = 0;
+	struct mlx5e_priv *priv = netdev_priv(netdev);
+	skb_frag_t org_frags[MAX_SKB_FRAGS];
+	struct mlx5e_nvmeotcp_queue *queue;
+	struct nvmeotcp_queue_entry *nqe;
+	int org_nr_frags, frag_index;
+	struct mlx5e_cqe128 *cqe128;
+	u32 queue_id;
+
+	queue_id = (be32_to_cpu(cqe->sop_drop_qpn) & MLX5E_TC_FLOW_ID_MASK);
+	queue = mlx5e_nvmeotcp_get_queue(priv->nvmeotcp, queue_id);
+	if (unlikely(!queue)) {
+		dev_kfree_skb_any(skb);
+		return NULL;
+	}
+
+	cqe128 = container_of(cqe, struct mlx5e_cqe128, cqe64);
+	if (cqe_is_nvmeotcp_resync(cqe)) {
+		nvmeotcp_update_resync(queue, cqe128);
+		mlx5e_nvmeotcp_put_queue(queue);
+		return skb;
+	}
+
+#ifdef CONFIG_TCP_DDP_CRC
+	/* If a resync occurred in the previous cqe,
+	 * the current cqe.crcvalid bit may not be valid,
+	 * so we will treat it as 0
+	 */
+	skb->ddp_crc = queue->after_resync_cqe ? 0 :
+		cqe_is_nvmeotcp_crcvalid(cqe);
+	queue->after_resync_cqe = 0;
+#endif
+	if (!cqe_is_nvmeotcp_zc(cqe)) {
+		mlx5e_nvmeotcp_put_queue(queue);
+		return skb;
+	}
+
+	/* cc ddp from cqe */
+	ccid = be16_to_cpu(cqe128->ccid);
+	ccoff = be32_to_cpu(cqe128->ccoff);
+	cclen = be16_to_cpu(cqe128->cclen);
+	hlen  = be16_to_cpu(cqe128->hlen);
+
+	/* carve a hole in the skb for DDP data */
+	if (linear) {
+		skb_trim(skb, hlen);
+	} else {
+		org_nr_frags = skb_shinfo(skb)->nr_frags;
+		mlx5_nvmeotcp_trim_nonlinear(skb, org_frags, &frag_index,
+					     cclen);
+	}
+
+	nqe = &queue->ccid_table[ccid];
+
+	/* packet starts new ccid? */
+	if (queue->ccid != ccid || queue->ccid_gen != nqe->ccid_gen) {
+		queue->ccid = ccid;
+		queue->ccoff = 0;
+		queue->ccoff_inner = 0;
+		queue->ccsglidx = 0;
+		queue->ccid_gen = nqe->ccid_gen;
+	}
+
+	/* skip inside cc until the ccoff in the cqe */
+	while (queue->ccoff + queue->ccoff_inner < ccoff) {
+		remaining = nqe->sgl[queue->ccsglidx].length - queue->ccoff_inner;
+		fragsz = min_t(off_t, remaining,
+			       ccoff - (queue->ccoff + queue->ccoff_inner));
+
+		if (fragsz == remaining)
+			mlx5e_nvmeotcp_advance_sgl_iter(queue);
+		else
+			queue->ccoff_inner += fragsz;
+	}
+
+	/* adjust the skb according to the cqe cc */
+	while (to_copy < cclen) {
+		if (skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS) {
+			dev_kfree_skb_any(skb);
+			mlx5e_nvmeotcp_put_queue(queue);
+			return NULL;
+		}
+
+		remaining = nqe->sgl[queue->ccsglidx].length - queue->ccoff_inner;
+		fragsz = min_t(int, remaining, cclen - to_copy);
+
+		mlx5e_nvmeotcp_add_skb_frag(netdev, skb, queue, nqe, fragsz);
+		to_copy += fragsz;
+		if (fragsz == remaining)
+			mlx5e_nvmeotcp_advance_sgl_iter(queue);
+		else
+			queue->ccoff_inner += fragsz;
+	}
+
+	if (cqe_bcnt > hlen + cclen) {
+		remaining = cqe_bcnt - hlen - cclen;
+		if (linear)
+			skb = mlx5_nvmeotcp_add_tail(queue, skb,
+						     offset_in_page(skb->data) +
+								hlen + cclen,
+						     remaining);
+		else
+			skb = mlx5_nvmeotcp_add_tail_nonlinear(queue, skb,
+							       org_frags,
+							       org_nr_frags,
+							       frag_index);
+	}
+
+	mlx5e_nvmeotcp_put_queue(queue);
+	return skb;
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp_rxtx.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp_rxtx.h
new file mode 100644
index 000000000000..65456b46c33f
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp_rxtx.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2021 Mellanox Technologies. */
+#ifndef __MLX5E_NVMEOTCP_RXTX_H__
+#define __MLX5E_NVMEOTCP_RXTX_H__
+
+#ifdef CONFIG_MLX5_EN_NVMEOTCP
+
+#include <linux/skbuff.h>
+#include "en.h"
+
+struct sk_buff*
+mlx5e_nvmeotcp_handle_rx_skb(struct net_device *netdev, struct sk_buff *skb,
+			     struct mlx5_cqe64 *cqe, u32 cqe_bcnt, bool linear);
+
+static inline int mlx5_nvmeotcp_get_headlen(struct mlx5_cqe64 *cqe, u32 cqe_bcnt)
+{
+	struct mlx5e_cqe128 *cqe128;
+
+	if (!cqe_is_nvmeotcp_zc(cqe) || cqe_is_nvmeotcp_resync(cqe))
+		return cqe_bcnt;
+
+	cqe128 = container_of(cqe, struct mlx5e_cqe128, cqe64);
+	return be16_to_cpu(cqe128->hlen);
+}
+
+#else
+static inline struct sk_buff*
+mlx5e_nvmeotcp_handle_rx_skb(struct net_device *netdev, struct sk_buff *skb,
+			     struct mlx5_cqe64 *cqe, u32 cqe_bcnt, bool linear)
+{ return skb; }
+
+static inline int mlx5_nvmeotcp_get_headlen(struct mlx5_cqe64 *cqe, u32 cqe_bcnt)
+{ return cqe_bcnt; }
+
+#endif /* CONFIG_MLX5_EN_NVMEOTCP */
+
+static inline u16 mlx5e_get_headlen_hint(struct mlx5_cqe64 *cqe, u32 cqe_bcnt)
+{
+	return min_t(u32, MLX5E_RX_MAX_HEAD, mlx5_nvmeotcp_get_headlen(cqe, cqe_bcnt));
+}
+
+
+#endif /* __MLX5E_NVMEOTCP_RXTX_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
index 598d62366af2..168a4f490b8d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -48,6 +48,7 @@
 #include "en_accel/ipsec_rxtx.h"
 #include "en_accel/tls_rxtx.h"
 #include "en_accel/nvmeotcp.h"
+#include "en_accel/nvmeotcp_rxtx.h"
 #include "lib/clock.h"
 #include "en/xdp.h"
 #include "en/xsk/rx.h"
@@ -57,9 +58,11 @@
 
 static struct sk_buff *
 mlx5e_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
+				struct mlx5_cqe64 *cqe,
 				u16 cqe_bcnt, u32 head_offset, u32 page_idx);
 static struct sk_buff *
 mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
+				   struct mlx5_cqe64 *cqe,
 				   u16 cqe_bcnt, u32 head_offset, u32 page_idx);
 static void mlx5e_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe);
 static void mlx5e_handle_rx_cqe_mpwrq(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe);
@@ -1189,6 +1192,12 @@ mlx5e_skb_from_cqe_linear(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe,
 	/* queue up for recycling/reuse */
 	page_ref_inc(di->page);
 
+#if defined(CONFIG_TCP_DDP) && defined(CONFIG_MLX5_EN_NVMEOTCP)
+	if (cqe_is_nvmeotcp(cqe))
+		skb = mlx5e_nvmeotcp_handle_rx_skb(rq->netdev, skb, cqe,
+						   cqe_bcnt, true);
+#endif
+
 	return skb;
 }
 
@@ -1197,8 +1206,8 @@ mlx5e_skb_from_cqe_nonlinear(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe,
 			     struct mlx5e_wqe_frag_info *wi, u32 cqe_bcnt)
 {
 	struct mlx5e_rq_frag_info *frag_info = &rq->wqe.info.arr[0];
+	u16 headlen = mlx5e_get_headlen_hint(cqe, cqe_bcnt);
 	struct mlx5e_wqe_frag_info *head_wi = wi;
-	u16 headlen      = min_t(u32, MLX5E_RX_MAX_HEAD, cqe_bcnt);
 	u16 frag_headlen = headlen;
 	u16 byte_cnt     = cqe_bcnt - headlen;
 	struct sk_buff *skb;
@@ -1207,7 +1216,7 @@ mlx5e_skb_from_cqe_nonlinear(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe,
 	 * might spread among multiple pages.
 	 */
 	skb = napi_alloc_skb(rq->cq.napi,
-			     ALIGN(MLX5E_RX_MAX_HEAD, sizeof(long)));
+			     ALIGN(headlen, sizeof(long)));
 	if (unlikely(!skb)) {
 		rq->stats->buff_alloc_err++;
 		return NULL;
@@ -1233,6 +1242,12 @@ mlx5e_skb_from_cqe_nonlinear(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe,
 	skb->tail += headlen;
 	skb->len  += headlen;
 
+#if defined(CONFIG_TCP_DDP) && defined(CONFIG_MLX5_EN_NVMEOTCP)
+	if (cqe_is_nvmeotcp(cqe))
+		skb = mlx5e_nvmeotcp_handle_rx_skb(rq->netdev, skb, cqe,
+						   cqe_bcnt, false);
+#endif
+
 	return skb;
 }
 
@@ -1387,7 +1402,7 @@ static void mlx5e_handle_rx_cqe_mpwrq_rep(struct mlx5e_rq *rq, struct mlx5_cqe64
 	skb = INDIRECT_CALL_2(rq->mpwqe.skb_from_cqe_mpwrq,
 			      mlx5e_skb_from_cqe_mpwrq_linear,
 			      mlx5e_skb_from_cqe_mpwrq_nonlinear,
-			      rq, wi, cqe_bcnt, head_offset, page_idx);
+			      rq, wi, cqe, cqe_bcnt, head_offset, page_idx);
 	if (!skb)
 		goto mpwrq_cqe_out;
 
@@ -1418,17 +1433,18 @@ const struct mlx5e_rx_handlers mlx5e_rx_handlers_rep = {
 
 static struct sk_buff *
 mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
+				   struct mlx5_cqe64 *cqe,
 				   u16 cqe_bcnt, u32 head_offset, u32 page_idx)
 {
-	u16 headlen = min_t(u16, MLX5E_RX_MAX_HEAD, cqe_bcnt);
 	struct mlx5e_dma_info *di = &wi->umr.dma_info[page_idx];
+	u16 headlen = mlx5e_get_headlen_hint(cqe, cqe_bcnt);
 	u32 frag_offset    = head_offset + headlen;
 	u32 byte_cnt       = cqe_bcnt - headlen;
 	struct mlx5e_dma_info *head_di = di;
 	struct sk_buff *skb;
 
 	skb = napi_alloc_skb(rq->cq.napi,
-			     ALIGN(MLX5E_RX_MAX_HEAD, sizeof(long)));
+			     ALIGN(headlen, sizeof(long)));
 	if (unlikely(!skb)) {
 		rq->stats->buff_alloc_err++;
 		return NULL;
@@ -1459,11 +1475,18 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *w
 	skb->tail += headlen;
 	skb->len  += headlen;
 
+#if defined(CONFIG_TCP_DDP) && defined(CONFIG_MLX5_EN_NVMEOTCP)
+	if (cqe_is_nvmeotcp(cqe))
+		skb = mlx5e_nvmeotcp_handle_rx_skb(rq->netdev, skb, cqe,
+						   cqe_bcnt, false);
+#endif
+
 	return skb;
 }
 
 static struct sk_buff *
 mlx5e_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
+				struct mlx5_cqe64 *cqe,
 				u16 cqe_bcnt, u32 head_offset, u32 page_idx)
 {
 	struct mlx5e_dma_info *di = &wi->umr.dma_info[page_idx];
@@ -1505,6 +1528,12 @@ mlx5e_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
 	/* queue up for recycling/reuse */
 	page_ref_inc(di->page);
 
+#if defined(CONFIG_TCP_DDP) && defined(CONFIG_MLX5_EN_NVMEOTCP)
+	if (cqe_is_nvmeotcp(cqe))
+		skb = mlx5e_nvmeotcp_handle_rx_skb(rq->netdev, skb, cqe,
+						   cqe_bcnt, true);
+#endif
+
 	return skb;
 }
 
@@ -1543,7 +1572,7 @@ static void mlx5e_handle_rx_cqe_mpwrq(struct mlx5e_rq *rq, struct mlx5_cqe64 *cq
 	skb = INDIRECT_CALL_2(rq->mpwqe.skb_from_cqe_mpwrq,
 			      mlx5e_skb_from_cqe_mpwrq_linear,
 			      mlx5e_skb_from_cqe_mpwrq_nonlinear,
-			      rq, wi, cqe_bcnt, head_offset, page_idx);
+			      rq, wi, cqe, cqe_bcnt, head_offset, page_idx);
 	if (!skb)
 		goto mpwrq_cqe_out;
 
-- 
2.24.1



From borisp at mellanox.com  Thu Jan 14 10:10:33 2021
From: borisp at mellanox.com (Boris Pismenny)
Date: Thu, 14 Jan 2021 17:10:33 +0200
Subject: [PATCH v2 net-next 21/21] Documentation: add TCP DDP offload
 documentation
In-Reply-To: <20210114151033.13020-1-borisp@mellanox.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
Message-ID: <20210114151033.13020-22-borisp@mellanox.com>

Add documentation to describe NIC direct data placement offload
for protocol layered over TCP. Use NVMe-TCP as an example.
---
 Documentation/networking/index.rst           |   1 +
 Documentation/networking/tcp-ddp-offload.rst | 296 +++++++++++++++++++
 2 files changed, 297 insertions(+)
 create mode 100644 Documentation/networking/tcp-ddp-offload.rst

diff --git a/Documentation/networking/index.rst b/Documentation/networking/index.rst
index b8a29997d433..99644159a0cc 100644
--- a/Documentation/networking/index.rst
+++ b/Documentation/networking/index.rst
@@ -99,6 +99,7 @@ Contents:
    sysfs-tagging
    tc-actions-env-rules
    tcp-thin
+   tcp-ddp-offload
    team
    timestamping
    tipc
diff --git a/Documentation/networking/tcp-ddp-offload.rst b/Documentation/networking/tcp-ddp-offload.rst
new file mode 100644
index 000000000000..1607e8210968
--- /dev/null
+++ b/Documentation/networking/tcp-ddp-offload.rst
@@ -0,0 +1,296 @@
+.. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+
+=================================
+TCP direct data placement offload
+=================================
+
+Overview
+========
+
+The Linux kernel TCP direct data placement (DDP) offload infrastructure
+provides tagged request-response protocols, such as NVMe-TCP, the ability to
+place response data directly in pre-registered buffers according to header
+tags. DDP is particularly useful for data-intensive pipelined protocols whose
+responses may be reordered.
+
+For example, in NVMe-TCP numerous read requests are sent together and each
+request is tagged using the PDU header CID field. Receiving servers process
+requests as fast as possible and sometimes responses for smaller requests
+bypasses responses to larger requests, i.e., read 4KB bypasses read 1GB.
+Thereafter, clients corrleate responses to requests using PDU header CID tags.
+The processing of each response requires copying data from SKBs to read
+request destination buffers; The offload avoids this copy. The offload is
+oblivious to destination buffers which can reside either in userspace
+(O_DIRECT) or in kernel pagecache.
+
+Request TCP byte-stream:
+
+.. parsed-literal::
+
+ +---------------+-------+---------------+-------+---------------+-------+
+ | PDU hdr CID=1 | Req 1 | PDU hdr CID=2 | Req 2 | PDU hdr CID=3 | Req 3 |
+ +---------------+-------+---------------+-------+---------------+-------+
+
+Response TCP byte-stream:
+
+.. parsed-literal::
+
+ +---------------+--------+---------------+--------+---------------+--------+
+ | PDU hdr CID=2 | Resp 2 | PDU hdr CID=3 | Resp 3 | PDU hdr CID=1 | Resp 1 |
+ +---------------+--------+---------------+--------+---------------+--------+
+
+Offloading requires no new SKB bits. Instead, the driver builds SKB page
+fragments that point destination buffers. Consequently, SKBs represent the
+original data on the wire, which enables *transparent* inter-operation with the
+network stack.  To avoid copies between SKBs and destination buffers, the
+layer-5 protocol (L5P) will check ``if (src == dst)`` for SKB page fragments,
+success indicates that data is already placed there by NIC hardware and copy
+should be skipped.
+
+Offloading does require NIC hardware to track L5P procotol framing, similarly
+to RX TLS offload (see documentation at
+:ref:`Documentation/networking/tls-offload.rst <tls_offload>`).  NIC hardware
+will parse PDU headers extract fields such as operation type, length, ,tag
+identifier, etc. and offload only segments that correspond to tags registered
+with the NIC, see the :ref:`buf_reg` section.
+
+Device configuration
+====================
+
+During driver initialization the device sets the ``NETIF_F_HW_TCP_DDP`` and
+feature and installs its
+:c:type:`struct tcp_ddp_ops <tcp_ddp_ops>`
+pointer in the :c:member:`tcp_ddp_ops` member of the
+:c:type:`struct net_device <net_device>`.
+
+Later, after the L5P completes its handshake offload is installed on the socket.
+If offload installation fails, then the connection is handled by software as if
+offload was not attempted. Offload installation should configure 
+
+To request offload for a socket `sk`, the L5P calls :c:member:`tcp_ddp_sk_add`:
+
+.. code-block:: c
+
+ int (*tcp_ddp_sk_add)(struct net_device *netdev,
+ 		      struct sock *sk,
+ 		      struct tcp_ddp_config *config);
+
+The function return 0 for success. In case of failure, L5P software should
+fallback to normal non-offloaded operation.  The `config` parameter indicates
+the L5P type and any metadata relevant for that protocol. For example, in
+NVMe-TCP the following config is used:
+
+.. code-block:: c
+
+ /**
+  * struct nvme_tcp_ddp_config - nvme tcp ddp configuration for an IO queue
+  *
+  * @pfv:        pdu version (e.g., NVME_TCP_PFV_1_0)
+  * @cpda:       controller pdu data alignmend (dwords, 0's based)
+  * @dgst:       digest types enabled.
+  *              The netdev will offload crc if ddp_crc is supported.
+  * @queue_size: number of nvme-tcp IO queue elements
+  * @queue_id:   queue identifier
+  * @cpu_io:     cpu core running the IO thread for this queue
+  */
+ struct nvme_tcp_ddp_config {
+ 	struct tcp_ddp_config   cfg;
+ 
+ 	u16			pfv;
+ 	u8			cpda;
+ 	u8			dgst;
+ 	int			queue_size;
+ 	int			queue_id;
+ 	int			io_cpu;
+ };
+
+When offload is not needed anymore, e.g., the socket is being released, the L5P
+calls :c:member:`tcp_ddp_sk_del` to release device contexts:
+
+.. code-block:: c
+
+ void (*tcp_ddp_sk_del)(struct net_device *netdev,
+  		        struct sock *sk);
+
+Normal operation
+================
+
+At the very least, the device maintains the following state for each connection:
+
+ * 5-tuple
+ * expected TCP sequence number
+ * mapping between tags and corresponding buffers
+ * current offset within PDU, PDU length, current PDU tag
+
+NICs should not assume any correleation between PDUs and TCP packets.  Assuming
+that TCP packets arrive in-order, offload will place PDU payload directly
+inside corresponding registered buffers. No packets are to be delayed by NIC
+offload. If offload is not possible, than the packet is to be passed as-is to
+software. To perform offload on incoming packets without buffering packets in
+the NIC, the NIC stores some inter-packet state, such as partial PDU headers.
+
+RX data-path
+------------
+
+After the device validates TCP checksums, it can perform DDP offload.  The
+packet is steered to the DDP offload context according to the 5-tuple.
+Thereafter, the expected TCP sequence number is checked against the packet's
+TCP sequence number. If there's a match, then offload is performed: PDU payload
+is DMA written to corresponding destination buffer according to the PDU header
+tag.  The data should be DMAed only once, and the NIC receive ring will only
+store the remaining TCP and PDU headers.
+
+We remark that a single TCP packet may have numerous PDUs embedded inside. NICs
+can choose to offload one or more of these PDUs according to various
+trade-offs. Possibly, offloading such small PDUs is of little value, and it is
+better to leave it to software.
+
+Upon receiving a DDP offloaded packet, the driver reconstructs the original SKB
+using page frags, while pointing to the destination buffers whenever possible.
+This method enables seemless integration with the network stack, which can
+inspect and modify packet fields transperently to the offload.
+
+.. _buf_reg:
+
+Destination buffer registration
+-------------------------------
+
+To register the mapping betwteen tags and destination buffers for a socket
+`sk`, the L5P calls :c:member:`tcp_ddp_setup` of :c:type:`struct tcp_ddp_ops
+<tcp_ddp_ops>`:
+
+.. code-block:: c
+  
+ int (*tcp_ddp_setup)(struct net_device *netdev,
+ 		     struct sock *sk,
+ 		     struct tcp_ddp_io *io);
+
+
+The `io` provides the buffer via scatter-gather list (`sg_table`) and
+corresponding tag (`command_id`):
+
+.. code-block:: c
+ /**
+  * struct tcp_ddp_io - tcp ddp configuration for an IO request.
+  *
+  * @command_id:  identifier on the wire associated with these buffers
+  * @nents:       number of entries in the sg_table
+  * @sg_table:    describing the buffers for this IO request
+  * @first_sgl:   first SGL in sg_table
+  */
+ struct tcp_ddp_io {
+ 	u32			command_id;
+ 	int			nents;
+ 	struct sg_table		sg_table;
+ 	struct scatterlist	first_sgl[SG_CHUNK_SIZE];
+ };
+
+After the buffers have been consumed by the L5P, to release the NIC mapping of
+buffers the L5P calls :c:member:`tcp_ddp_teardown` of :c:type:`struct
+tcp_ddp_ops <tcp_ddp_ops>`: 
+
+.. code-block:: c
+  
+ int (*tcp_ddp_teardown)(struct net_device *netdev,
+ 			struct sock *sk,
+ 			struct tcp_ddp_io *io,
+ 			void *ddp_ctx);
+
+`tcp_ddp_teardown` receives the same `io` context and an additional opaque
+`ddp_ctx` that is used for asynchronous teardown, see the :ref:`async_release`
+section.
+
+.. _async_release:
+
+Asynchronous teardown
+---------------------
+
+To teardown the association between tags and buffers and allow tag reuse NIC HW
+is called by the NIC driver during `tcp_ddp_teardown`. This operation may be
+performed either synchronously or asynchronously. In asynchronous teardown,
+`tcp_ddp_teardown` returns immediately without unmapping NIC HW buffers. Later,
+when the unmapping completes by NIC HW, the NIC driver will call up to L5P
+using :c:member:`ddp_teardown_done` of :c:type:`struct tcp_ddp_ulp_ops`:
+
+.. code-block:: c
+
+ void (*ddp_teardown_done)(void *ddp_ctx);
+
+The `ddp_ctx` parameter passed in `ddp_teardown_done` is the same on provided
+in `tcp_ddp_teardown` and it is used to carry some context about the buffers
+and tags that are released.
+
+Resync handling
+===============
+
+In presence of packet drops or network packet reordering, the device may lose
+synchronization between the TCP stream and the L5P framing, and require a
+resync with the kernel's TCP stack. When the device is out of sync, no offload
+takes place, and packets are passed as-is to software. (resync is very similar
+to TLS offload (see documentation at
+:ref:`Documentation/networking/tls-offload.rst <tls_offload>`)
+
+If only packets with L5P data are lost or reordered, then resynchronization may
+be avoided by NIC HW that keeps tracking PDU headers. If, however, PDU headers
+are reordered, then resynchronization is necessary.
+
+To resynchronize hardware during traffic, we use a handshake between hardware
+and software. The NIC HW searches for a sequence of bytes that identifies L5P
+headers (i.e., magic pattern).  For example, in NVMe-TCP, the PDU operation
+type can be used for this purpose.  Using the PDU header length field, the NIC
+HW will continue to find and match magic patterns in subsequent PDU headers. If
+the pattern is missing in an expected position, then searching for the pattern
+starts anew.
+
+The NIC will not resume offload when the magic pattern is first identified.
+Instead, it will request L5P software to confirm that indeed this is a PDU
+header. To request confirmation the NIC driver calls up to L5P using
+:c:member:`*resync_request` of :c:type:`struct tcp_ddp_ulp_ops`:
+
+.. code-block:: c
+
+  bool (*resync_request)(struct sock *sk, u32 seq, u32 flags);
+
+The `seq` field contains the TCP sequence of the last byte in the PDU header.
+L5P software will respond to this request after observing the packet containing
+TCP sequence `seq` in-order. If the PDU header is indeed there, then L5P
+software calls the NIC driver using the :c:member:`tcp_ddp_resync` function of
+the :c:type:`struct tcp_ddp_ops <tcp_ddp_ops>` inside the :c:type:`struct
+net_device <net_device>` while passing the same `seq` to confirm it is a PDU
+header.
+
+.. code-block:: c
+
+ void (*tcp_ddp_resync)(struct net_device *netdev,
+ 		       struct sock *sk, u32 seq);
+
+Statistics
+==========
+
+Per L5P protocol, the following NIC driver must report statistics for the above
+netdevice operations and packets processed by offload. For example, NVMe-TCP
+offload reports:
+
+ * ``rx_nvmeotcp_queue_init`` - number of NVMe-TCP offload contexts created.
+ * ``rx_nvmeotcp_queue_teardown`` - number of NVMe-TCP offload contexts
+   destroyed.
+ * ``rx_nvmeotcp_ddp_setup`` - number of DDP buffers mapped.
+ * ``rx_nvmeotcp_ddp_setup_fail`` - number of DDP buffers mapping that failed.
+ * ``rx_nvmeotcp_ddp_teardown`` - number of DDP buffers unmapped.
+ * ``rx_nvmeotcp_drop`` - number of packets dropped in the driver due to fatal
+   errors.
+ * ``rx_nvmeotcp_resync`` - number of packets with resync requests.
+ * ``rx_nvmeotcp_offload_packets`` - number of packets that used offload.
+ * ``rx_nvmeotcp_offload_bytes`` - number of bytes placed in DDP buffers.
+
+NIC requirements
+================
+
+NIC hardware should meet the following requirements to provide this offload:
+
+ * Offload must never buffer TCP packets.
+ * Offload must never modify TCP packet headers.
+ * Offload must never reorder TCP packets within a flow.
+ * Offload must never drop TCP packets.
+ * Offload must not depend on any TCP fields beyond the
+   5-tuple and TCP sequence number.
-- 
2.24.1



From edumazet at google.com  Thu Jan 14 10:57:32 2021
From: edumazet at google.com (Eric Dumazet)
Date: Thu, 14 Jan 2021 16:57:32 +0100
Subject: [PATCH v2 net-next 02/21] net: Introduce direct data placement
 tcp offload
In-Reply-To: <20210114151033.13020-3-borisp@mellanox.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
 <20210114151033.13020-3-borisp@mellanox.com>
Message-ID: <CANn89iJaFRFxVe-eV7hcwC_5Zp+HtWHxTQt+BNYcKOwZUriSDg@mail.gmail.com>

On Thu, Jan 14, 2021 at 4:10 PM Boris Pismenny <borisp at mellanox.com> wrote:
>
> This commit introduces direct data placement offload for TCP.
> This capability is accompanied by new net_device operations that
> configure hardware contexts. There is a context per socket, and a context per DDP
> opreation. Additionally, a resynchronization routine is used to assist
> hardware handle TCP OOO, and continue the offload.
> Furthermore, we let the offloading driver advertise what is the max hw
> sectors/segments.
>
> Using this interface, the NIC hardware will scatter TCP payload directly
> to the BIO pages according to the command_id.
> To maintain the correctness of the network stack, the driver is expected
> to construct SKBs that point to the BIO pages.
>
> This, the SKB represents the data on the wire, while it is pointing
> to data that is already placed in the destination buffer.
> As a result, data from page frags should not be copied out to
> the linear part.
>
> As SKBs that use DDP are already very memory efficient, we modify
> skb_condence to avoid copying data from fragments to the linear
> part of SKBs that belong to a socket that uses DDP offload.
>
> A follow-up patch will use this interface for DDP in NVMe-TCP.
>
> Signed-off-by: Boris Pismenny <borisp at mellanox.com>
> Signed-off-by: Ben Ben-Ishay <benishay at mellanox.com>
> Signed-off-by: Or Gerlitz <ogerlitz at mellanox.com>
> Signed-off-by: Yoray Zack <yorayz at mellanox.com>
> ---
>  include/linux/netdev_features.h    |   2 +
>  include/linux/netdevice.h          |   5 ++
>  include/net/inet_connection_sock.h |   4 +
>  include/net/tcp_ddp.h              | 136 +++++++++++++++++++++++++++++
>  net/Kconfig                        |   9 ++
>  net/core/skbuff.c                  |   9 +-
>  net/ethtool/common.c               |   1 +
>  7 files changed, 165 insertions(+), 1 deletion(-)
>  create mode 100644 include/net/tcp_ddp.h
>
> diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h
> index 934de56644e7..fb35dcac03d2 100644
> --- a/include/linux/netdev_features.h
> +++ b/include/linux/netdev_features.h
> @@ -84,6 +84,7 @@ enum {
>         NETIF_F_GRO_FRAGLIST_BIT,       /* Fraglist GRO */
>
>         NETIF_F_HW_MACSEC_BIT,          /* Offload MACsec operations */
> +       NETIF_F_HW_TCP_DDP_BIT,         /* TCP direct data placement offload */
>
>         /*
>          * Add your fresh new feature above and remember to update
> @@ -157,6 +158,7 @@ enum {
>  #define NETIF_F_GRO_FRAGLIST   __NETIF_F(GRO_FRAGLIST)
>  #define NETIF_F_GSO_FRAGLIST   __NETIF_F(GSO_FRAGLIST)
>  #define NETIF_F_HW_MACSEC      __NETIF_F(HW_MACSEC)
> +#define NETIF_F_HW_TCP_DDP     __NETIF_F(HW_TCP_DDP)
>
>  /* Finds the next feature with the highest number of the range of start till 0.
>   */
> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> index 259be67644e3..3dd3cdf5dec3 100644
> --- a/include/linux/netdevice.h
> +++ b/include/linux/netdevice.h
> @@ -941,6 +941,7 @@ struct dev_ifalias {
>
>  struct devlink;
>  struct tlsdev_ops;
> +struct tcp_ddp_dev_ops;
>
>  struct netdev_name_node {
>         struct hlist_node hlist;
> @@ -1937,6 +1938,10 @@ struct net_device {
>         const struct tlsdev_ops *tlsdev_ops;
>  #endif
>
> +#ifdef CONFIG_TCP_DDP
> +       const struct tcp_ddp_dev_ops *tcp_ddp_ops;
> +#endif
> +
>         const struct header_ops *header_ops;
>
>         unsigned int            flags;
> diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h
> index 7338b3865a2a..a08b85b53aa8 100644
> --- a/include/net/inet_connection_sock.h
> +++ b/include/net/inet_connection_sock.h
> @@ -66,6 +66,8 @@ struct inet_connection_sock_af_ops {
>   * @icsk_ulp_ops          Pluggable ULP control hook
>   * @icsk_ulp_data         ULP private data
>   * @icsk_clean_acked      Clean acked data hook
> + * @icsk_ulp_ddp_ops      Pluggable ULP direct data placement control hook
> + * @icsk_ulp_ddp_data     ULP direct data placement private data
>   * @icsk_listen_portaddr_node  hash to the portaddr listener hashtable
>   * @icsk_ca_state:        Congestion control state
>   * @icsk_retransmits:     Number of unrecovered [RTO] timeouts
> @@ -94,6 +96,8 @@ struct inet_connection_sock {
>         const struct tcp_ulp_ops  *icsk_ulp_ops;
>         void __rcu                *icsk_ulp_data;
>         void (*icsk_clean_acked)(struct sock *sk, u32 acked_seq);

#ifdef CONFIG_TCP_DDP ?

> +       const struct tcp_ddp_ulp_ops  *icsk_ulp_ddp_ops;
> +       void __rcu                *icsk_ulp_ddp_data;
>         struct hlist_node         icsk_listen_portaddr_node;
>         unsigned int              (*icsk_sync_mss)(struct sock *sk, u32 pmtu);
>         __u8                      icsk_ca_state:5,
> diff --git a/include/net/tcp_ddp.h b/include/net/tcp_ddp.h
> new file mode 100644
> index 000000000000..31e5b1a16d0f
> --- /dev/null
> +++ b/include/net/tcp_ddp.h
> @@ -0,0 +1,136 @@
> +/* SPDX-License-Identifier: GPL-2.0
> + *
> + * tcp_ddp.h
> + *     Author: Boris Pismenny <borisp at mellanox.com>
> + *     Copyright (C) 2021 Mellanox Technologies.
> + */
> +#ifndef _TCP_DDP_H
> +#define _TCP_DDP_H
> +
> +#include <linux/netdevice.h>
> +#include <net/inet_connection_sock.h>
> +#include <net/sock.h>
> +
> +/* limits returned by the offload driver, zero means don't care */
> +struct tcp_ddp_limits {
> +       int      max_ddp_sgl_len;
> +};
> +
> +enum tcp_ddp_type {
> +       TCP_DDP_NVME = 1,
> +};
> +
> +/**
> + * struct tcp_ddp_config - Generic tcp ddp configuration: tcp ddp IO queue
> + * config implementations must use this as the first member.
> + * Add new instances of tcp_ddp_config below (nvme-tcp, etc.).
> + */
> +struct tcp_ddp_config {
> +       enum tcp_ddp_type    type;
> +       unsigned char        buf[];
> +};
> +
> +/**
> + * struct nvme_tcp_ddp_config - nvme tcp ddp configuration for an IO queue
> + *
> + * @pfv:        pdu version (e.g., NVME_TCP_PFV_1_0)
> + * @cpda:       controller pdu data alignmend (dwords, 0's based)
> + * @dgst:       digest types enabled.
> + *              The netdev will offload crc if ddp_crc is supported.
> + * @queue_size: number of nvme-tcp IO queue elements
> + * @queue_id:   queue identifier
> + * @cpu_io:     cpu core running the IO thread for this queue
> + */
> +struct nvme_tcp_ddp_config {
> +       struct tcp_ddp_config   cfg;
> +
> +       u16                     pfv;
> +       u8                      cpda;
> +       u8                      dgst;
> +       int                     queue_size;
> +       int                     queue_id;
> +       int                     io_cpu;
> +};
> +
> +/**
> + * struct tcp_ddp_io - tcp ddp configuration for an IO request.
> + *
> + * @command_id:  identifier on the wire associated with these buffers
> + * @nents:       number of entries in the sg_table
> + * @sg_table:    describing the buffers for this IO request
> + * @first_sgl:   first SGL in sg_table
> + */
> +struct tcp_ddp_io {
> +       u32                     command_id;
> +       int                     nents;
> +       struct sg_table         sg_table;
> +       struct scatterlist      first_sgl[SG_CHUNK_SIZE];
> +};
> +
> +/* struct tcp_ddp_dev_ops - operations used by an upper layer protocol to configure ddp offload
> + *
> + * @tcp_ddp_limits:    limit the number of scatter gather entries per IO.
> + *                     the device driver can use this to limit the resources allocated per queue.
> + * @tcp_ddp_sk_add:    add offload for the queue represennted by the socket+config pair.
> + *                     this function is used to configure either copy, crc or both offloads.
> + * @tcp_ddp_sk_del:    remove offload from the socket, and release any device related resources.
> + * @tcp_ddp_setup:     request copy offload for buffers associated with a command_id in tcp_ddp_io.
> + * @tcp_ddp_teardown:  release offload resources association between buffers and command_id in
> + *                     tcp_ddp_io.
> + * @tcp_ddp_resync:    respond to the driver's resync_request. Called only if resync is successful.
> + */
> +struct tcp_ddp_dev_ops {
> +       int (*tcp_ddp_limits)(struct net_device *netdev,
> +                             struct tcp_ddp_limits *limits);
> +       int (*tcp_ddp_sk_add)(struct net_device *netdev,
> +                             struct sock *sk,
> +                             struct tcp_ddp_config *config);
> +       void (*tcp_ddp_sk_del)(struct net_device *netdev,
> +                              struct sock *sk);
> +       int (*tcp_ddp_setup)(struct net_device *netdev,
> +                            struct sock *sk,
> +                            struct tcp_ddp_io *io);
> +       int (*tcp_ddp_teardown)(struct net_device *netdev,
> +                               struct sock *sk,
> +                               struct tcp_ddp_io *io,
> +                               void *ddp_ctx);
> +       void (*tcp_ddp_resync)(struct net_device *netdev,
> +                              struct sock *sk, u32 seq);
> +};
> +
> +#define TCP_DDP_RESYNC_REQ BIT(0)
> +
> +/**
> + * struct tcp_ddp_ulp_ops - Interface to register uppper layer Direct Data Placement (DDP) TCP offload
> + */
> +struct tcp_ddp_ulp_ops {
> +       /* NIC requests ulp to indicate if @seq is the start of a message */
> +       bool (*resync_request)(struct sock *sk, u32 seq, u32 flags);
> +       /* NIC driver informs the ulp that ddp teardown is done - used for async completions*/
> +       void (*ddp_teardown_done)(void *ddp_ctx);
> +};
> +
> +/**
> + * struct tcp_ddp_ctx - Generic tcp ddp context: device driver per queue contexts must
> + * use this as the first member.
> + */
> +struct tcp_ddp_ctx {
> +       enum tcp_ddp_type    type;
> +       unsigned char        buf[];
> +};
> +
> +static inline struct tcp_ddp_ctx *tcp_ddp_get_ctx(const struct sock *sk)
> +{
> +       struct inet_connection_sock *icsk = inet_csk(sk);
> +
> +       return (__force struct tcp_ddp_ctx *)icsk->icsk_ulp_ddp_data;
> +}
> +
> +static inline void tcp_ddp_set_ctx(struct sock *sk, void *ctx)
> +{
> +       struct inet_connection_sock *icsk = inet_csk(sk);
> +
> +       rcu_assign_pointer(icsk->icsk_ulp_ddp_data, ctx);
> +}
> +
> +#endif //_TCP_DDP_H
> diff --git a/net/Kconfig b/net/Kconfig
> index f4c32d982af6..3876861cdc90 100644
> --- a/net/Kconfig
> +++ b/net/Kconfig
> @@ -457,6 +457,15 @@ config ETHTOOL_NETLINK
>           netlink. It provides better extensibility and some new features,
>           e.g. notification messages.
>
> +config TCP_DDP
> +       bool "TCP direct data placement offload"
> +       default n
> +       help
> +         Direct Data Placement (DDP) offload for TCP enables ULP, such as
> +         NVMe-TCP/iSCSI, to request the NIC to place TCP payload data
> +         of a command response directly into kernel pages.
> +
> +
>  endif   # if NET
>
>  # Used by archs to tell that they support BPF JIT compiler plus which flavour.
> diff --git a/net/core/skbuff.c b/net/core/skbuff.c
> index f62cae3f75d8..791c1b6bc067 100644
> --- a/net/core/skbuff.c
> +++ b/net/core/skbuff.c
> @@ -69,6 +69,7 @@
>  #include <net/xfrm.h>
>  #include <net/mpls.h>
>  #include <net/mptcp.h>
> +#include <net/tcp_ddp.h>
>
>  #include <linux/uaccess.h>
>  #include <trace/events/skb.h>
> @@ -6140,9 +6141,15 @@ EXPORT_SYMBOL(pskb_extract);
>   */
>  void skb_condense(struct sk_buff *skb)
>  {
> +       bool is_ddp = false;
> +
> +#ifdef CONFIG_TCP_DDP

This looks strange to me : TCP should call this helper while skb->sk is NULL

Are you sure this is not dead code ?

> +       is_ddp = skb->sk && inet_csk(skb->sk) &&
> +                inet_csk(skb->sk)->icsk_ulp_ddp_data;
> +#endif
>         if (skb->data_len) {
>                 if (skb->data_len > skb->end - skb->tail ||
> -                   skb_cloned(skb))
> +                   skb_cloned(skb) || is_ddp)
>                         return;
>
>                 /* Nice, we can free page frag(s) right now */
> diff --git a/net/ethtool/common.c b/net/ethtool/common.c
> index 24036e3055a1..a2ff7a4a6bbf 100644
> --- a/net/ethtool/common.c
> +++ b/net/ethtool/common.c
> @@ -68,6 +68,7 @@ const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] = {
>         [NETIF_F_HW_TLS_RX_BIT] =        "tls-hw-rx-offload",
>         [NETIF_F_GRO_FRAGLIST_BIT] =     "rx-gro-list",
>         [NETIF_F_HW_MACSEC_BIT] =        "macsec-hw-offload",
> +       [NETIF_F_HW_TCP_DDP_BIT] =       "tcp-ddp-offload",
>  };
>
>  const char
> --
> 2.24.1
>


From israelr at nvidia.com  Thu Jan 14 11:34:24 2021
From: israelr at nvidia.com (Israel Rukshin)
Date: Thu, 14 Jan 2021 18:34:24 +0200
Subject: [PATCH v2 1/2] nvme-rdma: avoid request double completion for
 concurrent nvme_rdma_timeout
In-Reply-To: <20210114090926.12109-2-lengchao@huawei.com>
References: <20210114090926.12109-1-lengchao@huawei.com>
 <20210114090926.12109-2-lengchao@huawei.com>
Message-ID: <ab0a9be7-778a-4fdb-4bd3-cad6c76534e4@nvidia.com>

On 1/14/2021 11:09 AM, Chao Leng wrote:
> A crash happens when inject completing request long time(nearly 30s).
> Each name space has a request queue, when inject completing request long
> time, multi request queues may have time out requests at the same time,
> nvme_rdma_timeout will execute concurrently. Multi requests in different
> request queues may be queued in the same rdma queue, multi
> nvme_rdma_timeout may call nvme_rdma_stop_queue at the same time.
> The first nvme_rdma_timeout will clear NVME_RDMA_Q_LIVE and continue
> stopping the rdma queue(drain qp), but the others check NVME_RDMA_Q_LIVE
> is already cleared, and then directly complete the requests, complete
> request before the qp is fully drained may lead to a use-after-free
> condition.
>
> Add a multex lock to serialize nvme_rdma_stop_queue.

Looks good to me.

I tested this patch at our regression.

Tested-by: Israel Rukshin <israelr at nvidia.com>
Reviewed-by: Israel Rukshin <israelr at nvidia.com>



From hch at lst.de  Thu Jan 14 12:33:13 2021
From: hch at lst.de (Christoph Hellwig)
Date: Thu, 14 Jan 2021 18:33:13 +0100
Subject: [PATCH] nvme: allow use of cmb on v1.4 controllers
In-Reply-To: <20210114132441.193782-1-its@irrelevant.dk>
References: <20210114132441.193782-1-its@irrelevant.dk>
Message-ID: <20210114173313.GA31028@lst.de>

On Thu, Jan 14, 2021 at 02:24:41PM +0100, Klaus Jensen wrote:
> From: Klaus Jensen <k.jensen at samsung.com>
> 
> Since NVMe v1.4 the Controller Memory Buffer must be explicitly enabled
> by the host.

Thanks, this has been on my TODO list for a while.

> +	vs = readl(dev->bar + NVME_REG_VS);
> +
> +	if (vs >= NVME_VS(1, 4, 0)) {
> +		if (!NVME_CAP_CMBS(dev->ctrl.cap))
> +			return;

We should not check the version here, but the presence of the new
register so that controllers claiming an older version complicance
that implement the new scheme are supported as well.

Given that the old scheme is highly dangerous in virtualized enviroments
we should also warn about it and eventually required an explicit opt-in
to use it.

> +	if (vs >= NVME_VS(1, 4, 0)) {
> +		cmbmsc = pci_resource_start(pdev, bar);
> +		cmbmsc |= (NVME_CMBMSC_CRE | NVME_CMBMSC_CMSE);
> +
> +		/*
> +		 * Writing the low bits may cause the controller to check the
> +		 * validity of the 52 bit controller base address in the CMBMSC
> +		 * register, so write the high bits first.
> +		 */
> +		writel(cmbmsc >> 32, dev->bar + NVME_REG_CMBMSC + 4);
> +		writel(cmbmsc, dev->bar + NVME_REG_CMBMSC);

I think we should just use writeq here, with the hilo wrapper for 32-bit
platforms here.  The reason why NVMe has so avoided the 64-bit access
is for buggy Apple controllers, but they are unlikely to implement CMB.


From hch at infradead.org  Thu Jan 14 12:35:46 2021
From: hch at infradead.org (Christoph Hellwig)
Date: Thu, 14 Jan 2021 17:35:46 +0000
Subject: fabrics connect cmd with a non-zero reserved value
In-Reply-To: <69465d48-5a63-5c49-50aa-39c4f921ed4a@grimberg.me>
References: <SN6PR1901MB202957C808A7D493E252D873EED00@SN6PR1901MB2029.namprd19.prod.outlook.com>
 <6e271be1-088b-5a23-0eec-23578f707c28@grimberg.me>
 <69465d48-5a63-5c49-50aa-39c4f921ed4a@grimberg.me>
Message-ID: <20210114173546.GA1872345@infradead.org>

On Wed, Jan 13, 2021 at 05:10:05PM -0800, Sagi Grimberg wrote:
> OK, now I see the issue.
> 
> This appears to me this would be an issue with the spec. As the connect
> data (like any command payload) is coming in the form of an sgl.

Reserved fields in host to controller data structure may be checked,
but may also not.  So we can verify anyting we think is to bogus to
pass, but there is not requirement for the controller to check every
reserved field or bit.


From hch at lst.de  Thu Jan 14 12:40:28 2021
From: hch at lst.de (Christoph Hellwig)
Date: Thu, 14 Jan 2021 18:40:28 +0100
Subject: [PATCH 0/3] few simple cleanups for nvme-tcp host
In-Reply-To: <20210114001039.1644461-1-sagi@grimberg.me>
References: <20210114001039.1644461-1-sagi@grimberg.me>
Message-ID: <20210114174028.GA31188@lst.de>

I saw no actual patches in reply to this cover letter..


From hch at lst.de  Thu Jan 14 12:43:11 2021
From: hch at lst.de (Christoph Hellwig)
Date: Thu, 14 Jan 2021 18:43:11 +0100
Subject: [PATCH] nvme: reject the ns when the block size is smaller
 than a sector
In-Reply-To: <87698545-de26-c0ca-01e9-4dc2ddcacc80@grimberg.me>
References: <20210113160621.98615-1-fengli@smartx.com>
 <SN4PR0401MB35985C08E5FFCDF0F5817A9D9BA90@SN4PR0401MB3598.namprd04.prod.outlook.com>
 <87698545-de26-c0ca-01e9-4dc2ddcacc80@grimberg.me>
Message-ID: <20210114174311.GB31188@lst.de>

On Wed, Jan 13, 2021 at 02:12:59PM -0800, Sagi Grimberg wrote:
>> But this only catches a physical block size < 512 for NVMe, not any other block device.
>>
>> Please fix it for the general case in blk_queue_physical_block_size().
>
> We actually call that later and would probably be better to check here..

We had a series for that a short while ago that got lost.


From hch at lst.de  Thu Jan 14 12:52:08 2021
From: hch at lst.de (Christoph Hellwig)
Date: Thu, 14 Jan 2021 18:52:08 +0100
Subject: [PATCH 1/1] nvme: update enumerations for status codes
In-Reply-To: <20210104125947.160984-1-mgurtovoy@nvidia.com>
References: <20210104125947.160984-1-mgurtovoy@nvidia.com>
Message-ID: <20210114175208.GA31438@lst.de>

Can we use this as a chance to resync with nvme-cli and have one
version of the header that works for both?


From Amit.Engel at Dell.com  Thu Jan 14 12:45:05 2021
From: Amit.Engel at Dell.com (Engel, Amit)
Date: Thu, 14 Jan 2021 17:45:05 +0000
Subject: fabrics connect cmd with a non-zero reserved value
In-Reply-To: <20210114173546.GA1872345@infradead.org>
References: <SN6PR1901MB202957C808A7D493E252D873EED00@SN6PR1901MB2029.namprd19.prod.outlook.com>
 <6e271be1-088b-5a23-0eec-23578f707c28@grimberg.me>
 <69465d48-5a63-5c49-50aa-39c4f921ed4a@grimberg.me>
 <20210114173546.GA1872345@infradead.org>
Message-ID: <SN6PR1901MB202982AC06FA1A12157B9837EEA80@SN6PR1901MB2029.namprd19.prod.outlook.com>

Since the data is coming in the form of an sgl, the reserved bits that the spec defines are not really reserved.
I would expect that the spec will not mark the second byte of connect cmd as reserved
(These reserved bits are not cleared to 0h)

-----Original Message-----
From: Christoph Hellwig <hch at infradead.org> 
Sent: Thursday, January 14, 2021 7:36 PM
To: Sagi Grimberg
Cc: Engel, Amit; linux-nvme at lists.infradead.org; Anner, Ran; Frederick.Knight at netapp.com; Grupi, Elad
Subject: Re: fabrics connect cmd with a non-zero reserved value


[EXTERNAL EMAIL] 

On Wed, Jan 13, 2021 at 05:10:05PM -0800, Sagi Grimberg wrote:
> OK, now I see the issue.
> 
> This appears to me this would be an issue with the spec. As the 
> connect data (like any command payload) is coming in the form of an sgl.

Reserved fields in host to controller data structure may be checked, but may also not.  So we can verify anyting we think is to bogus to pass, but there is not requirement for the controller to check every reserved field or bit.


From kbusch at kernel.org  Thu Jan 14 13:06:00 2021
From: kbusch at kernel.org (Keith Busch)
Date: Thu, 14 Jan 2021 10:06:00 -0800
Subject: [PATCH] nvme: allow use of cmb on v1.4 controllers
In-Reply-To: <20210114132441.193782-1-its@irrelevant.dk>
References: <20210114132441.193782-1-its@irrelevant.dk>
Message-ID: <20210114180600.GA1511435@dhcp-10-100-145-180.wdc.com>

On Thu, Jan 14, 2021 at 02:24:41PM +0100, Klaus Jensen wrote:
> @@ -1795,6 +1796,15 @@ static void nvme_map_cmb(struct nvme_dev *dev)
>  	if (dev->cmb_size)
>  		return;
>  
> +	vs = readl(dev->bar + NVME_REG_VS);
> +
> +	if (vs >= NVME_VS(1, 4, 0)) {
> +		if (!NVME_CAP_CMBS(dev->ctrl.cap))
> +			return;
> +
> +		writel(NVME_CMBMSC_CRE, dev->bar + NVME_REG_CMBMSC);
> +	}
> +
>  	dev->cmbsz = readl(dev->bar + NVME_REG_CMBSZ);
>  	if (!dev->cmbsz)
>  		return;
> @@ -1805,6 +1815,19 @@ static void nvme_map_cmb(struct nvme_dev *dev)
>  	bar = NVME_CMB_BIR(dev->cmbloc);
>  	bar_size = pci_resource_len(pdev, bar);
>  
> +	if (vs >= NVME_VS(1, 4, 0)) {
> +		cmbmsc = pci_resource_start(pdev, bar);

Shouldn't this have a '+ offset' in case the CMB doesn't start at the
beginning of the bar?

> +		cmbmsc |= (NVME_CMBMSC_CRE | NVME_CMBMSC_CMSE);
> +
> +		/*
> +		 * Writing the low bits may cause the controller to check the
> +		 * validity of the 52 bit controller base address in the CMBMSC
> +		 * register, so write the high bits first.
> +		 */
> +		writel(cmbmsc >> 32, dev->bar + NVME_REG_CMBMSC + 4);
> +		writel(cmbmsc, dev->bar + NVME_REG_CMBMSC);

hi_lo_writeq()?

This should probably come after we've verified the '(offset > bar_size)'
check below so that we're not enabling these capabilities before we know
if they're within the BAR.

> +	}
> +
>  	if (offset > bar_size)
>  		return;


From kbusch at kernel.org  Thu Jan 14 13:15:15 2021
From: kbusch at kernel.org (Keith Busch)
Date: Thu, 14 Jan 2021 10:15:15 -0800
Subject: [PATCH] nvme: allow use of cmb on v1.4 controllers
In-Reply-To: <20210114180600.GA1511435@dhcp-10-100-145-180.wdc.com>
References: <20210114132441.193782-1-its@irrelevant.dk>
 <20210114180600.GA1511435@dhcp-10-100-145-180.wdc.com>
Message-ID: <20210114181515.GA1511450@dhcp-10-100-145-180.wdc.com>

On Thu, Jan 14, 2021 at 10:06:00AM -0800, Keith Busch wrote:
> On Thu, Jan 14, 2021 at 02:24:41PM +0100, Klaus Jensen wrote:
> > @@ -1795,6 +1796,15 @@ static void nvme_map_cmb(struct nvme_dev *dev)
> >  	if (dev->cmb_size)
> >  		return;
> >  
> > +	vs = readl(dev->bar + NVME_REG_VS);
> > +
> > +	if (vs >= NVME_VS(1, 4, 0)) {
> > +		if (!NVME_CAP_CMBS(dev->ctrl.cap))
> > +			return;
> > +
> > +		writel(NVME_CMBMSC_CRE, dev->bar + NVME_REG_CMBMSC);
> > +	}
> > +
> >  	dev->cmbsz = readl(dev->bar + NVME_REG_CMBSZ);
> >  	if (!dev->cmbsz)
> >  		return;
> > @@ -1805,6 +1815,19 @@ static void nvme_map_cmb(struct nvme_dev *dev)
> >  	bar = NVME_CMB_BIR(dev->cmbloc);
> >  	bar_size = pci_resource_len(pdev, bar);
> >  
> > +	if (vs >= NVME_VS(1, 4, 0)) {
> > +		cmbmsc = pci_resource_start(pdev, bar);
> 
> Shouldn't this have a '+ offset' in case the CMB doesn't start at the
> beginning of the bar?

One other thing, I believe pci_bus_address() is required instead of
pci_resource_start().


From borispismenny at gmail.com  Thu Jan 14 14:17:43 2021
From: borispismenny at gmail.com (Boris Pismenny)
Date: Thu, 14 Jan 2021 21:17:43 +0200
Subject: [PATCH v1 net-next 00/15] nvme-tcp receive offloads
In-Reply-To: <69f9a7c3-e2ab-454a-2713-2e9c9dea4e47@grimberg.me>
References: <20201207210649.19194-1-borisp@mellanox.com>
 <69f9a7c3-e2ab-454a-2713-2e9c9dea4e47@grimberg.me>
Message-ID: <6b9da1e6-c4d0-7853-15fb-edf655ead33f@gmail.com>

On 14/01/2021 3:27, Sagi Grimberg wrote:
> Hey Boris, sorry for some delays on my end...
> 
> I saw some long discussions on this set with David, what is
> the status here?
> 

The main purpose of this series is to address these.

> I'll take some more look into the patches, but if you
> addressed the feedback from the last iteration I don't
> expect major issues with this patch set (at least from
> nvme-tcp side).
> 
>> Changes since RFC v1:
>> =========================================
>> * Split mlx5 driver patches to several commits
>> * Fix nvme-tcp handling of recovery flows. In particular, move queue offlaod
>>    init/teardown to the start/stop functions.
> 
> I'm assuming that you tested controller resets and network hiccups
> during traffic right?
> 

Network hiccups were tested through netem packet drops and reordering.
We tested error recovery by taking the controller down and bringing it
back up while the system is quiescent and during traffic.

If you have another test in mind, please let me know.


From borispismenny at gmail.com  Thu Jan 14 14:21:47 2021
From: borispismenny at gmail.com (Boris Pismenny)
Date: Thu, 14 Jan 2021 21:21:47 +0200
Subject: [PATCH v1 net-next 00/15] nvme-tcp receive offloads
In-Reply-To: <967ae867-42c9-731d-9cb1-2c81fcc1ef77@gmail.com>
References: <20201207210649.19194-1-borisp@mellanox.com>
 <69f9a7c3-e2ab-454a-2713-2e9c9dea4e47@grimberg.me>
 <967ae867-42c9-731d-9cb1-2c81fcc1ef77@gmail.com>
Message-ID: <a14d5ab8-e62c-65ac-3b8b-0e657226625f@gmail.com>



On 14/01/2021 6:47, David Ahern wrote:
> On 1/13/21 6:27 PM, Sagi Grimberg wrote:
>>> Changes since RFC v1:
>>> =========================================
>>> * Split mlx5 driver patches to several commits
>>> * Fix nvme-tcp handling of recovery flows. In particular, move queue
>>> offlaod
>>> ?? init/teardown to the start/stop functions.
>>
>> I'm assuming that you tested controller resets and network hiccups
>> during traffic right?
> 
> I had questions on this part as well -- e.g., what happens on a TCP
> retry? packets arrive, sgl filled for the command id, but packet is
> dropped in the stack (e.g., enqueue backlog is filled, so packet gets
> dropped)
> 

On re-transmission the HW context's expected tcp sequence number doesn't
match. As a result, the received packet is un-offloaded and software
will do the copy/crc for its data.

As a general rule, if HW context expected sequence numbers don't match,
then there's no offload.


From hch at infradead.org  Thu Jan 14 14:29:48 2021
From: hch at infradead.org (Christoph Hellwig)
Date: Thu, 14 Jan 2021 20:29:48 +0100
Subject: [GIT PULL] nvme fixes for 5.11
Message-ID: <YACbrIes4r8Qa1mA@infradead.org>

The following changes since commit 5342fd4255021ef0c4ce7be52eea1c4ebda11c63:

  bcache: set bcache device into read-only mode for BCH_FEATURE_INCOMPAT_OBSO_LARGE_BUCKET (2021-01-09 09:21:03 -0700)

are available in the Git repository at:

  git://git.infradead.org/nvme.git tags/nvme-5.11-2021-01-14

for you to fetch changes up to 5ab25a32cd90ce561ac28b9302766e565d61304c:

  nvme: don't intialize hwmon for discovery controllers (2021-01-14 20:27:35 +0100)

----------------------------------------------------------------
nvme fixes for 5.11:

 - don't initialize hwmon for discover controllers (Sagi Grimberg)
 - fix iov_iter handling in nvme-tcp (Sagi Grimberg)
 - fix a preempt warning in nvme-tcp (Sagi Grimberg)
 - fix a possible NULL pointer dereference in nvme (Israel Rukshin)

----------------------------------------------------------------
Israel Rukshin (1):
      nvmet-rdma: Fix NULL deref when setting pi_enable and traddr INADDR_ANY

Sagi Grimberg (3):
      nvme-tcp: Fix warning with CONFIG_DEBUG_PREEMPT
      nvme-tcp: fix possible data corruption with bio merges
      nvme: don't intialize hwmon for discovery controllers

 drivers/nvme/host/core.c   | 11 ++++++++---
 drivers/nvme/host/tcp.c    |  4 ++--
 drivers/nvme/target/rdma.c | 16 ++++++++--------
 3 files changed, 18 insertions(+), 13 deletions(-)


From borispismenny at gmail.com  Thu Jan 14 15:19:25 2021
From: borispismenny at gmail.com (Boris Pismenny)
Date: Thu, 14 Jan 2021 22:19:25 +0200
Subject: [PATCH v2 net-next 02/21] net: Introduce direct data placement
 tcp offload
In-Reply-To: <CANn89iJaFRFxVe-eV7hcwC_5Zp+HtWHxTQt+BNYcKOwZUriSDg@mail.gmail.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
 <20210114151033.13020-3-borisp@mellanox.com>
 <CANn89iJaFRFxVe-eV7hcwC_5Zp+HtWHxTQt+BNYcKOwZUriSDg@mail.gmail.com>
Message-ID: <62d4606a-0a41-2b12-cf16-3523d0b73573@gmail.com>



On 14/01/2021 17:57, Eric Dumazet wrote:
> On Thu, Jan 14, 2021 at 4:10 PM Boris Pismenny <borisp at mellanox.com> wrote:
>>
>> This commit introduces direct data placement offload for TCP.
>> This capability is accompanied by new net_device operations that
>> configure hardware contexts. There is a context per socket, and a context per DDP
>> opreation. Additionally, a resynchronization routine is used to assist
>> hardware handle TCP OOO, and continue the offload.
>> Furthermore, we let the offloading driver advertise what is the max hw
>> sectors/segments.
>>
>> Using this interface, the NIC hardware will scatter TCP payload directly
>> to the BIO pages according to the command_id.
>> To maintain the correctness of the network stack, the driver is expected
>> to construct SKBs that point to the BIO pages.
>>
>> This, the SKB represents the data on the wire, while it is pointing
>> to data that is already placed in the destination buffer.
>> As a result, data from page frags should not be copied out to
>> the linear part.
>>
>> As SKBs that use DDP are already very memory efficient, we modify
>> skb_condence to avoid copying data from fragments to the linear
>> part of SKBs that belong to a socket that uses DDP offload.
>>
>> A follow-up patch will use this interface for DDP in NVMe-TCP.
>>
>> Signed-off-by: Boris Pismenny <borisp at mellanox.com>
>> Signed-off-by: Ben Ben-Ishay <benishay at mellanox.com>
>> Signed-off-by: Or Gerlitz <ogerlitz at mellanox.com>
>> Signed-off-by: Yoray Zack <yorayz at mellanox.com>
>> ---
>>  include/linux/netdev_features.h    |   2 +
>>  include/linux/netdevice.h          |   5 ++
>>  include/net/inet_connection_sock.h |   4 +
>>  include/net/tcp_ddp.h              | 136 +++++++++++++++++++++++++++++
>>  net/Kconfig                        |   9 ++
>>  net/core/skbuff.c                  |   9 +-
>>  net/ethtool/common.c               |   1 +
>>  7 files changed, 165 insertions(+), 1 deletion(-)
>>  create mode 100644 include/net/tcp_ddp.h
>>
>> diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h
>> index 934de56644e7..fb35dcac03d2 100644
>> --- a/include/linux/netdev_features.h
>> +++ b/include/linux/netdev_features.h
>> @@ -84,6 +84,7 @@ enum {
>>         NETIF_F_GRO_FRAGLIST_BIT,       /* Fraglist GRO */
>>
>>         NETIF_F_HW_MACSEC_BIT,          /* Offload MACsec operations */
>> +       NETIF_F_HW_TCP_DDP_BIT,         /* TCP direct data placement offload */
>>
>>         /*
>>          * Add your fresh new feature above and remember to update
>> @@ -157,6 +158,7 @@ enum {
>>  #define NETIF_F_GRO_FRAGLIST   __NETIF_F(GRO_FRAGLIST)
>>  #define NETIF_F_GSO_FRAGLIST   __NETIF_F(GSO_FRAGLIST)
>>  #define NETIF_F_HW_MACSEC      __NETIF_F(HW_MACSEC)
>> +#define NETIF_F_HW_TCP_DDP     __NETIF_F(HW_TCP_DDP)
>>
>>  /* Finds the next feature with the highest number of the range of start till 0.
>>   */
>> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
>> index 259be67644e3..3dd3cdf5dec3 100644
>> --- a/include/linux/netdevice.h
>> +++ b/include/linux/netdevice.h
>> @@ -941,6 +941,7 @@ struct dev_ifalias {
>>
>>  struct devlink;
>>  struct tlsdev_ops;
>> +struct tcp_ddp_dev_ops;
>>
>>  struct netdev_name_node {
>>         struct hlist_node hlist;
>> @@ -1937,6 +1938,10 @@ struct net_device {
>>         const struct tlsdev_ops *tlsdev_ops;
>>  #endif
>>
>> +#ifdef CONFIG_TCP_DDP
>> +       const struct tcp_ddp_dev_ops *tcp_ddp_ops;
>> +#endif
>> +
>>         const struct header_ops *header_ops;
>>
>>         unsigned int            flags;
>> diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h
>> index 7338b3865a2a..a08b85b53aa8 100644
>> --- a/include/net/inet_connection_sock.h
>> +++ b/include/net/inet_connection_sock.h
>> @@ -66,6 +66,8 @@ struct inet_connection_sock_af_ops {
>>   * @icsk_ulp_ops          Pluggable ULP control hook
>>   * @icsk_ulp_data         ULP private data
>>   * @icsk_clean_acked      Clean acked data hook
>> + * @icsk_ulp_ddp_ops      Pluggable ULP direct data placement control hook
>> + * @icsk_ulp_ddp_data     ULP direct data placement private data
>>   * @icsk_listen_portaddr_node  hash to the portaddr listener hashtable
>>   * @icsk_ca_state:        Congestion control state
>>   * @icsk_retransmits:     Number of unrecovered [RTO] timeouts
>> @@ -94,6 +96,8 @@ struct inet_connection_sock {
>>         const struct tcp_ulp_ops  *icsk_ulp_ops;
>>         void __rcu                *icsk_ulp_data;
>>         void (*icsk_clean_acked)(struct sock *sk, u32 acked_seq);
> 
> #ifdef CONFIG_TCP_DDP ?
> 
>> +       const struct tcp_ddp_ulp_ops  *icsk_ulp_ddp_ops;
>> +       void __rcu                *icsk_ulp_ddp_data;
>>         struct hlist_node         icsk_listen_portaddr_node;
>>         unsigned int              (*icsk_sync_mss)(struct sock *sk, u32 pmtu);
>>         __u8                      icsk_ca_state:5,
>> diff --git a/include/net/tcp_ddp.h b/include/net/tcp_ddp.h
>> new file mode 100644
>> index 000000000000..31e5b1a16d0f
>> --- /dev/null
>> +++ b/include/net/tcp_ddp.h
>> @@ -0,0 +1,136 @@
>> +/* SPDX-License-Identifier: GPL-2.0
>> + *
>> + * tcp_ddp.h
>> + *     Author: Boris Pismenny <borisp at mellanox.com>
>> + *     Copyright (C) 2021 Mellanox Technologies.
>> + */
>> +#ifndef _TCP_DDP_H
>> +#define _TCP_DDP_H
>> +
>> +#include <linux/netdevice.h>
>> +#include <net/inet_connection_sock.h>
>> +#include <net/sock.h>
>> +
>> +/* limits returned by the offload driver, zero means don't care */
>> +struct tcp_ddp_limits {
>> +       int      max_ddp_sgl_len;
>> +};
>> +
>> +enum tcp_ddp_type {
>> +       TCP_DDP_NVME = 1,
>> +};
>> +
>> +/**
>> + * struct tcp_ddp_config - Generic tcp ddp configuration: tcp ddp IO queue
>> + * config implementations must use this as the first member.
>> + * Add new instances of tcp_ddp_config below (nvme-tcp, etc.).
>> + */
>> +struct tcp_ddp_config {
>> +       enum tcp_ddp_type    type;
>> +       unsigned char        buf[];
>> +};
>> +
>> +/**
>> + * struct nvme_tcp_ddp_config - nvme tcp ddp configuration for an IO queue
>> + *
>> + * @pfv:        pdu version (e.g., NVME_TCP_PFV_1_0)
>> + * @cpda:       controller pdu data alignmend (dwords, 0's based)
>> + * @dgst:       digest types enabled.
>> + *              The netdev will offload crc if ddp_crc is supported.
>> + * @queue_size: number of nvme-tcp IO queue elements
>> + * @queue_id:   queue identifier
>> + * @cpu_io:     cpu core running the IO thread for this queue
>> + */
>> +struct nvme_tcp_ddp_config {
>> +       struct tcp_ddp_config   cfg;
>> +
>> +       u16                     pfv;
>> +       u8                      cpda;
>> +       u8                      dgst;
>> +       int                     queue_size;
>> +       int                     queue_id;
>> +       int                     io_cpu;
>> +};
>> +
>> +/**
>> + * struct tcp_ddp_io - tcp ddp configuration for an IO request.
>> + *
>> + * @command_id:  identifier on the wire associated with these buffers
>> + * @nents:       number of entries in the sg_table
>> + * @sg_table:    describing the buffers for this IO request
>> + * @first_sgl:   first SGL in sg_table
>> + */
>> +struct tcp_ddp_io {
>> +       u32                     command_id;
>> +       int                     nents;
>> +       struct sg_table         sg_table;
>> +       struct scatterlist      first_sgl[SG_CHUNK_SIZE];
>> +};
>> +
>> +/* struct tcp_ddp_dev_ops - operations used by an upper layer protocol to configure ddp offload
>> + *
>> + * @tcp_ddp_limits:    limit the number of scatter gather entries per IO.
>> + *                     the device driver can use this to limit the resources allocated per queue.
>> + * @tcp_ddp_sk_add:    add offload for the queue represennted by the socket+config pair.
>> + *                     this function is used to configure either copy, crc or both offloads.
>> + * @tcp_ddp_sk_del:    remove offload from the socket, and release any device related resources.
>> + * @tcp_ddp_setup:     request copy offload for buffers associated with a command_id in tcp_ddp_io.
>> + * @tcp_ddp_teardown:  release offload resources association between buffers and command_id in
>> + *                     tcp_ddp_io.
>> + * @tcp_ddp_resync:    respond to the driver's resync_request. Called only if resync is successful.
>> + */
>> +struct tcp_ddp_dev_ops {
>> +       int (*tcp_ddp_limits)(struct net_device *netdev,
>> +                             struct tcp_ddp_limits *limits);
>> +       int (*tcp_ddp_sk_add)(struct net_device *netdev,
>> +                             struct sock *sk,
>> +                             struct tcp_ddp_config *config);
>> +       void (*tcp_ddp_sk_del)(struct net_device *netdev,
>> +                              struct sock *sk);
>> +       int (*tcp_ddp_setup)(struct net_device *netdev,
>> +                            struct sock *sk,
>> +                            struct tcp_ddp_io *io);
>> +       int (*tcp_ddp_teardown)(struct net_device *netdev,
>> +                               struct sock *sk,
>> +                               struct tcp_ddp_io *io,
>> +                               void *ddp_ctx);
>> +       void (*tcp_ddp_resync)(struct net_device *netdev,
>> +                              struct sock *sk, u32 seq);
>> +};
>> +
>> +#define TCP_DDP_RESYNC_REQ BIT(0)
>> +
>> +/**
>> + * struct tcp_ddp_ulp_ops - Interface to register uppper layer Direct Data Placement (DDP) TCP offload
>> + */
>> +struct tcp_ddp_ulp_ops {
>> +       /* NIC requests ulp to indicate if @seq is the start of a message */
>> +       bool (*resync_request)(struct sock *sk, u32 seq, u32 flags);
>> +       /* NIC driver informs the ulp that ddp teardown is done - used for async completions*/
>> +       void (*ddp_teardown_done)(void *ddp_ctx);
>> +};
>> +
>> +/**
>> + * struct tcp_ddp_ctx - Generic tcp ddp context: device driver per queue contexts must
>> + * use this as the first member.
>> + */
>> +struct tcp_ddp_ctx {
>> +       enum tcp_ddp_type    type;
>> +       unsigned char        buf[];
>> +};
>> +
>> +static inline struct tcp_ddp_ctx *tcp_ddp_get_ctx(const struct sock *sk)
>> +{
>> +       struct inet_connection_sock *icsk = inet_csk(sk);
>> +
>> +       return (__force struct tcp_ddp_ctx *)icsk->icsk_ulp_ddp_data;
>> +}
>> +
>> +static inline void tcp_ddp_set_ctx(struct sock *sk, void *ctx)
>> +{
>> +       struct inet_connection_sock *icsk = inet_csk(sk);
>> +
>> +       rcu_assign_pointer(icsk->icsk_ulp_ddp_data, ctx);
>> +}
>> +
>> +#endif //_TCP_DDP_H
>> diff --git a/net/Kconfig b/net/Kconfig
>> index f4c32d982af6..3876861cdc90 100644
>> --- a/net/Kconfig
>> +++ b/net/Kconfig
>> @@ -457,6 +457,15 @@ config ETHTOOL_NETLINK
>>           netlink. It provides better extensibility and some new features,
>>           e.g. notification messages.
>>
>> +config TCP_DDP
>> +       bool "TCP direct data placement offload"
>> +       default n
>> +       help
>> +         Direct Data Placement (DDP) offload for TCP enables ULP, such as
>> +         NVMe-TCP/iSCSI, to request the NIC to place TCP payload data
>> +         of a command response directly into kernel pages.
>> +
>> +
>>  endif   # if NET
>>
>>  # Used by archs to tell that they support BPF JIT compiler plus which flavour.
>> diff --git a/net/core/skbuff.c b/net/core/skbuff.c
>> index f62cae3f75d8..791c1b6bc067 100644
>> --- a/net/core/skbuff.c
>> +++ b/net/core/skbuff.c
>> @@ -69,6 +69,7 @@
>>  #include <net/xfrm.h>
>>  #include <net/mpls.h>
>>  #include <net/mptcp.h>
>> +#include <net/tcp_ddp.h>
>>
>>  #include <linux/uaccess.h>
>>  #include <trace/events/skb.h>
>> @@ -6140,9 +6141,15 @@ EXPORT_SYMBOL(pskb_extract);
>>   */
>>  void skb_condense(struct sk_buff *skb)
>>  {
>> +       bool is_ddp = false;
>> +
>> +#ifdef CONFIG_TCP_DDP
> 
> This looks strange to me : TCP should call this helper while skb->sk is NULL
> 
> Are you sure this is not dead code ?
> 

Will verify again on Sunday. AFAICT, early demux sets skb->sk before this code
is called. Just to clarify, the purpose of this code is to avoid skb condensing
data that is already placed into destination buffers.

>> +       is_ddp = skb->sk && inet_csk(skb->sk) &&
>> +                inet_csk(skb->sk)->icsk_ulp_ddp_data;
>> +#endif
>>         if (skb->data_len) {
>>                 if (skb->data_len > skb->end - skb->tail ||
>> -                   skb_cloned(skb))
>> +                   skb_cloned(skb) || is_ddp)
>>                         return;
>>
>>                 /* Nice, we can free page frag(s) right now */
>> diff --git a/net/ethtool/common.c b/net/ethtool/common.c
>> index 24036e3055a1..a2ff7a4a6bbf 100644
>> --- a/net/ethtool/common.c
>> +++ b/net/ethtool/common.c
>> @@ -68,6 +68,7 @@ const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] = {
>>         [NETIF_F_HW_TLS_RX_BIT] =        "tls-hw-rx-offload",
>>         [NETIF_F_GRO_FRAGLIST_BIT] =     "rx-gro-list",
>>         [NETIF_F_HW_MACSEC_BIT] =        "macsec-hw-offload",
>> +       [NETIF_F_HW_TCP_DDP_BIT] =       "tcp-ddp-offload",
>>  };
>>
>>  const char
>> --
>> 2.24.1
>>


From edumazet at google.com  Thu Jan 14 15:43:17 2021
From: edumazet at google.com (Eric Dumazet)
Date: Thu, 14 Jan 2021 21:43:17 +0100
Subject: [PATCH v2 net-next 02/21] net: Introduce direct data placement
 tcp offload
In-Reply-To: <62d4606a-0a41-2b12-cf16-3523d0b73573@gmail.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
 <20210114151033.13020-3-borisp@mellanox.com>
 <CANn89iJaFRFxVe-eV7hcwC_5Zp+HtWHxTQt+BNYcKOwZUriSDg@mail.gmail.com>
 <62d4606a-0a41-2b12-cf16-3523d0b73573@gmail.com>
Message-ID: <CANn89i+7HNP6o5TkR9WKW3QkuH0cCArETfGTis8PWPR64BTFEQ@mail.gmail.com>

On Thu, Jan 14, 2021 at 9:19 PM Boris Pismenny <borispismenny at gmail.com> wrote:
>
>
>
> On 14/01/2021 17:57, Eric Dumazet wrote:
> > On Thu, Jan 14, 2021 at 4:10 PM Boris Pismenny <borisp at mellanox.com> wrote:
> >>
> >> This commit introduces direct data placement offload for TCP.
> >> This capability is accompanied by new net_device operations that
> >> configure hardware contexts. There is a context per socket, and a context per DDP
> >> opreation. Additionally, a resynchronization routine is used to assist
> >> hardware handle TCP OOO, and continue the offload.
> >> Furthermore, we let the offloading driver advertise what is the max hw
> >> sectors/segments.
> >>
> >> Using this interface, the NIC hardware will scatter TCP payload directly
> >> to the BIO pages according to the command_id.
> >> To maintain the correctness of the network stack, the driver is expected
> >> to construct SKBs that point to the BIO pages.
> >>
> >> This, the SKB represents the data on the wire, while it is pointing
> >> to data that is already placed in the destination buffer.
> >> As a result, data from page frags should not be copied out to
> >> the linear part.
> >>
> >> As SKBs that use DDP are already very memory efficient, we modify
> >> skb_condence to avoid copying data from fragments to the linear
> >> part of SKBs that belong to a socket that uses DDP offload.
> >>
> >> A follow-up patch will use this interface for DDP in NVMe-TCP.
> >>
> >> Signed-off-by: Boris Pismenny <borisp at mellanox.com>
> >> Signed-off-by: Ben Ben-Ishay <benishay at mellanox.com>
> >> Signed-off-by: Or Gerlitz <ogerlitz at mellanox.com>
> >> Signed-off-by: Yoray Zack <yorayz at mellanox.com>
> >> ---
> >>  include/linux/netdev_features.h    |   2 +
> >>  include/linux/netdevice.h          |   5 ++
> >>  include/net/inet_connection_sock.h |   4 +
> >>  include/net/tcp_ddp.h              | 136 +++++++++++++++++++++++++++++
> >>  net/Kconfig                        |   9 ++
> >>  net/core/skbuff.c                  |   9 +-
> >>  net/ethtool/common.c               |   1 +
> >>  7 files changed, 165 insertions(+), 1 deletion(-)
> >>  create mode 100644 include/net/tcp_ddp.h
> >>
> >> diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h
> >> index 934de56644e7..fb35dcac03d2 100644
> >> --- a/include/linux/netdev_features.h
> >> +++ b/include/linux/netdev_features.h
> >> @@ -84,6 +84,7 @@ enum {
> >>         NETIF_F_GRO_FRAGLIST_BIT,       /* Fraglist GRO */
> >>
> >>         NETIF_F_HW_MACSEC_BIT,          /* Offload MACsec operations */
> >> +       NETIF_F_HW_TCP_DDP_BIT,         /* TCP direct data placement offload */
> >>
> >>         /*
> >>          * Add your fresh new feature above and remember to update
> >> @@ -157,6 +158,7 @@ enum {
> >>  #define NETIF_F_GRO_FRAGLIST   __NETIF_F(GRO_FRAGLIST)
> >>  #define NETIF_F_GSO_FRAGLIST   __NETIF_F(GSO_FRAGLIST)
> >>  #define NETIF_F_HW_MACSEC      __NETIF_F(HW_MACSEC)
> >> +#define NETIF_F_HW_TCP_DDP     __NETIF_F(HW_TCP_DDP)
> >>
> >>  /* Finds the next feature with the highest number of the range of start till 0.
> >>   */
> >> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> >> index 259be67644e3..3dd3cdf5dec3 100644
> >> --- a/include/linux/netdevice.h
> >> +++ b/include/linux/netdevice.h
> >> @@ -941,6 +941,7 @@ struct dev_ifalias {
> >>
> >>  struct devlink;
> >>  struct tlsdev_ops;
> >> +struct tcp_ddp_dev_ops;
> >>
> >>  struct netdev_name_node {
> >>         struct hlist_node hlist;
> >> @@ -1937,6 +1938,10 @@ struct net_device {
> >>         const struct tlsdev_ops *tlsdev_ops;
> >>  #endif
> >>
> >> +#ifdef CONFIG_TCP_DDP
> >> +       const struct tcp_ddp_dev_ops *tcp_ddp_ops;
> >> +#endif
> >> +
> >>         const struct header_ops *header_ops;
> >>
> >>         unsigned int            flags;
> >> diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h
> >> index 7338b3865a2a..a08b85b53aa8 100644
> >> --- a/include/net/inet_connection_sock.h
> >> +++ b/include/net/inet_connection_sock.h
> >> @@ -66,6 +66,8 @@ struct inet_connection_sock_af_ops {
> >>   * @icsk_ulp_ops          Pluggable ULP control hook
> >>   * @icsk_ulp_data         ULP private data
> >>   * @icsk_clean_acked      Clean acked data hook
> >> + * @icsk_ulp_ddp_ops      Pluggable ULP direct data placement control hook
> >> + * @icsk_ulp_ddp_data     ULP direct data placement private data
> >>   * @icsk_listen_portaddr_node  hash to the portaddr listener hashtable
> >>   * @icsk_ca_state:        Congestion control state
> >>   * @icsk_retransmits:     Number of unrecovered [RTO] timeouts
> >> @@ -94,6 +96,8 @@ struct inet_connection_sock {
> >>         const struct tcp_ulp_ops  *icsk_ulp_ops;
> >>         void __rcu                *icsk_ulp_data;
> >>         void (*icsk_clean_acked)(struct sock *sk, u32 acked_seq);
> >
> > #ifdef CONFIG_TCP_DDP ?
> >
> >> +       const struct tcp_ddp_ulp_ops  *icsk_ulp_ddp_ops;
> >> +       void __rcu                *icsk_ulp_ddp_data;
> >>         struct hlist_node         icsk_listen_portaddr_node;
> >>         unsigned int              (*icsk_sync_mss)(struct sock *sk, u32 pmtu);
> >>         __u8                      icsk_ca_state:5,
> >> diff --git a/include/net/tcp_ddp.h b/include/net/tcp_ddp.h
> >> new file mode 100644
> >> index 000000000000..31e5b1a16d0f
> >> --- /dev/null
> >> +++ b/include/net/tcp_ddp.h
> >> @@ -0,0 +1,136 @@
> >> +/* SPDX-License-Identifier: GPL-2.0
> >> + *
> >> + * tcp_ddp.h
> >> + *     Author: Boris Pismenny <borisp at mellanox.com>
> >> + *     Copyright (C) 2021 Mellanox Technologies.
> >> + */
> >> +#ifndef _TCP_DDP_H
> >> +#define _TCP_DDP_H
> >> +
> >> +#include <linux/netdevice.h>
> >> +#include <net/inet_connection_sock.h>
> >> +#include <net/sock.h>
> >> +
> >> +/* limits returned by the offload driver, zero means don't care */
> >> +struct tcp_ddp_limits {
> >> +       int      max_ddp_sgl_len;
> >> +};
> >> +
> >> +enum tcp_ddp_type {
> >> +       TCP_DDP_NVME = 1,
> >> +};
> >> +
> >> +/**
> >> + * struct tcp_ddp_config - Generic tcp ddp configuration: tcp ddp IO queue
> >> + * config implementations must use this as the first member.
> >> + * Add new instances of tcp_ddp_config below (nvme-tcp, etc.).
> >> + */
> >> +struct tcp_ddp_config {
> >> +       enum tcp_ddp_type    type;
> >> +       unsigned char        buf[];
> >> +};
> >> +
> >> +/**
> >> + * struct nvme_tcp_ddp_config - nvme tcp ddp configuration for an IO queue
> >> + *
> >> + * @pfv:        pdu version (e.g., NVME_TCP_PFV_1_0)
> >> + * @cpda:       controller pdu data alignmend (dwords, 0's based)
> >> + * @dgst:       digest types enabled.
> >> + *              The netdev will offload crc if ddp_crc is supported.
> >> + * @queue_size: number of nvme-tcp IO queue elements
> >> + * @queue_id:   queue identifier
> >> + * @cpu_io:     cpu core running the IO thread for this queue
> >> + */
> >> +struct nvme_tcp_ddp_config {
> >> +       struct tcp_ddp_config   cfg;
> >> +
> >> +       u16                     pfv;
> >> +       u8                      cpda;
> >> +       u8                      dgst;
> >> +       int                     queue_size;
> >> +       int                     queue_id;
> >> +       int                     io_cpu;
> >> +};
> >> +
> >> +/**
> >> + * struct tcp_ddp_io - tcp ddp configuration for an IO request.
> >> + *
> >> + * @command_id:  identifier on the wire associated with these buffers
> >> + * @nents:       number of entries in the sg_table
> >> + * @sg_table:    describing the buffers for this IO request
> >> + * @first_sgl:   first SGL in sg_table
> >> + */
> >> +struct tcp_ddp_io {
> >> +       u32                     command_id;
> >> +       int                     nents;
> >> +       struct sg_table         sg_table;
> >> +       struct scatterlist      first_sgl[SG_CHUNK_SIZE];
> >> +};
> >> +
> >> +/* struct tcp_ddp_dev_ops - operations used by an upper layer protocol to configure ddp offload
> >> + *
> >> + * @tcp_ddp_limits:    limit the number of scatter gather entries per IO.
> >> + *                     the device driver can use this to limit the resources allocated per queue.
> >> + * @tcp_ddp_sk_add:    add offload for the queue represennted by the socket+config pair.
> >> + *                     this function is used to configure either copy, crc or both offloads.
> >> + * @tcp_ddp_sk_del:    remove offload from the socket, and release any device related resources.
> >> + * @tcp_ddp_setup:     request copy offload for buffers associated with a command_id in tcp_ddp_io.
> >> + * @tcp_ddp_teardown:  release offload resources association between buffers and command_id in
> >> + *                     tcp_ddp_io.
> >> + * @tcp_ddp_resync:    respond to the driver's resync_request. Called only if resync is successful.
> >> + */
> >> +struct tcp_ddp_dev_ops {
> >> +       int (*tcp_ddp_limits)(struct net_device *netdev,
> >> +                             struct tcp_ddp_limits *limits);
> >> +       int (*tcp_ddp_sk_add)(struct net_device *netdev,
> >> +                             struct sock *sk,
> >> +                             struct tcp_ddp_config *config);
> >> +       void (*tcp_ddp_sk_del)(struct net_device *netdev,
> >> +                              struct sock *sk);
> >> +       int (*tcp_ddp_setup)(struct net_device *netdev,
> >> +                            struct sock *sk,
> >> +                            struct tcp_ddp_io *io);
> >> +       int (*tcp_ddp_teardown)(struct net_device *netdev,
> >> +                               struct sock *sk,
> >> +                               struct tcp_ddp_io *io,
> >> +                               void *ddp_ctx);
> >> +       void (*tcp_ddp_resync)(struct net_device *netdev,
> >> +                              struct sock *sk, u32 seq);
> >> +};
> >> +
> >> +#define TCP_DDP_RESYNC_REQ BIT(0)
> >> +
> >> +/**
> >> + * struct tcp_ddp_ulp_ops - Interface to register uppper layer Direct Data Placement (DDP) TCP offload
> >> + */
> >> +struct tcp_ddp_ulp_ops {
> >> +       /* NIC requests ulp to indicate if @seq is the start of a message */
> >> +       bool (*resync_request)(struct sock *sk, u32 seq, u32 flags);
> >> +       /* NIC driver informs the ulp that ddp teardown is done - used for async completions*/
> >> +       void (*ddp_teardown_done)(void *ddp_ctx);
> >> +};
> >> +
> >> +/**
> >> + * struct tcp_ddp_ctx - Generic tcp ddp context: device driver per queue contexts must
> >> + * use this as the first member.
> >> + */
> >> +struct tcp_ddp_ctx {
> >> +       enum tcp_ddp_type    type;
> >> +       unsigned char        buf[];
> >> +};
> >> +
> >> +static inline struct tcp_ddp_ctx *tcp_ddp_get_ctx(const struct sock *sk)
> >> +{
> >> +       struct inet_connection_sock *icsk = inet_csk(sk);
> >> +
> >> +       return (__force struct tcp_ddp_ctx *)icsk->icsk_ulp_ddp_data;
> >> +}
> >> +
> >> +static inline void tcp_ddp_set_ctx(struct sock *sk, void *ctx)
> >> +{
> >> +       struct inet_connection_sock *icsk = inet_csk(sk);
> >> +
> >> +       rcu_assign_pointer(icsk->icsk_ulp_ddp_data, ctx);
> >> +}
> >> +
> >> +#endif //_TCP_DDP_H
> >> diff --git a/net/Kconfig b/net/Kconfig
> >> index f4c32d982af6..3876861cdc90 100644
> >> --- a/net/Kconfig
> >> +++ b/net/Kconfig
> >> @@ -457,6 +457,15 @@ config ETHTOOL_NETLINK
> >>           netlink. It provides better extensibility and some new features,
> >>           e.g. notification messages.
> >>
> >> +config TCP_DDP
> >> +       bool "TCP direct data placement offload"
> >> +       default n
> >> +       help
> >> +         Direct Data Placement (DDP) offload for TCP enables ULP, such as
> >> +         NVMe-TCP/iSCSI, to request the NIC to place TCP payload data
> >> +         of a command response directly into kernel pages.
> >> +
> >> +
> >>  endif   # if NET
> >>
> >>  # Used by archs to tell that they support BPF JIT compiler plus which flavour.
> >> diff --git a/net/core/skbuff.c b/net/core/skbuff.c
> >> index f62cae3f75d8..791c1b6bc067 100644
> >> --- a/net/core/skbuff.c
> >> +++ b/net/core/skbuff.c
> >> @@ -69,6 +69,7 @@
> >>  #include <net/xfrm.h>
> >>  #include <net/mpls.h>
> >>  #include <net/mptcp.h>
> >> +#include <net/tcp_ddp.h>
> >>
> >>  #include <linux/uaccess.h>
> >>  #include <trace/events/skb.h>
> >> @@ -6140,9 +6141,15 @@ EXPORT_SYMBOL(pskb_extract);
> >>   */
> >>  void skb_condense(struct sk_buff *skb)
> >>  {
> >> +       bool is_ddp = false;
> >> +
> >> +#ifdef CONFIG_TCP_DDP
> >
> > This looks strange to me : TCP should call this helper while skb->sk is NULL
> >
> > Are you sure this is not dead code ?
> >
>
> Will verify again on Sunday. AFAICT, early demux sets skb->sk before this code
> is called.


First, early demux is optional.

Secondly, skb->sk is stolen in skb_steal_sock() if early demux was performed.


Just to clarify, the purpose of this code is to avoid skb condensing
> data that is already placed into destination buffers.

Then this has not been tested. This suggests this code could be
removed, I doubt that your target traffic would ever be 'condensed'.

>
> >> +       is_ddp = skb->sk && inet_csk(skb->sk) &&
> >> +                inet_csk(skb->sk)->icsk_ulp_ddp_data;
> >> +#endif
> >>         if (skb->data_len) {
> >>                 if (skb->data_len > skb->end - skb->tail ||
> >> -                   skb_cloned(skb))
> >> +                   skb_cloned(skb) || is_ddp)
> >>                         return;
> >>
> >>                 /* Nice, we can free page frag(s) right now */
> >> diff --git a/net/ethtool/common.c b/net/ethtool/common.c
> >> index 24036e3055a1..a2ff7a4a6bbf 100644
> >> --- a/net/ethtool/common.c
> >> +++ b/net/ethtool/common.c
> >> @@ -68,6 +68,7 @@ const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] = {
> >>         [NETIF_F_HW_TLS_RX_BIT] =        "tls-hw-rx-offload",
> >>         [NETIF_F_GRO_FRAGLIST_BIT] =     "rx-gro-list",
> >>         [NETIF_F_HW_MACSEC_BIT] =        "macsec-hw-offload",
> >> +       [NETIF_F_HW_TCP_DDP_BIT] =       "tcp-ddp-offload",
> >>  };
> >>
> >>  const char
> >> --
> >> 2.24.1
> >>


From sagi at grimberg.me  Thu Jan 14 16:07:34 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Thu, 14 Jan 2021 13:07:34 -0800
Subject: [PATCH v1 net-next 00/15] nvme-tcp receive offloads
In-Reply-To: <6b9da1e6-c4d0-7853-15fb-edf655ead33f@gmail.com>
References: <20201207210649.19194-1-borisp@mellanox.com>
 <69f9a7c3-e2ab-454a-2713-2e9c9dea4e47@grimberg.me>
 <6b9da1e6-c4d0-7853-15fb-edf655ead33f@gmail.com>
Message-ID: <02f12db0-4f66-8691-72cb-7531395c7990@grimberg.me>


>> Hey Boris, sorry for some delays on my end...
>>
>> I saw some long discussions on this set with David, what is
>> the status here?
>>
> 
> The main purpose of this series is to address these.
> 
>> I'll take some more look into the patches, but if you
>> addressed the feedback from the last iteration I don't
>> expect major issues with this patch set (at least from
>> nvme-tcp side).
>>
>>> Changes since RFC v1:
>>> =========================================
>>> * Split mlx5 driver patches to several commits
>>> * Fix nvme-tcp handling of recovery flows. In particular, move queue offlaod
>>>     init/teardown to the start/stop functions.
>>
>> I'm assuming that you tested controller resets and network hiccups
>> during traffic right?
>>
> 
> Network hiccups were tested through netem packet drops and reordering.
> We tested error recovery by taking the controller down and bringing it
> back up while the system is quiescent and during traffic.
> 
> If you have another test in mind, please let me know.

I suggest to also perform interface down/up during traffic both
on the host and the targets.

Other than that we should be in decent shape...


From sagi at grimberg.me  Thu Jan 14 16:12:10 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Thu, 14 Jan 2021 13:12:10 -0800
Subject: fabrics connect cmd with a non-zero reserved value
In-Reply-To: <SN6PR1901MB202982AC06FA1A12157B9837EEA80@SN6PR1901MB2029.namprd19.prod.outlook.com>
References: <SN6PR1901MB202957C808A7D493E252D873EED00@SN6PR1901MB2029.namprd19.prod.outlook.com>
 <6e271be1-088b-5a23-0eec-23578f707c28@grimberg.me>
 <69465d48-5a63-5c49-50aa-39c4f921ed4a@grimberg.me>
 <20210114173546.GA1872345@infradead.org>
 <SN6PR1901MB202982AC06FA1A12157B9837EEA80@SN6PR1901MB2029.namprd19.prod.outlook.com>
Message-ID: <f957564e-bb63-5c00-f2cc-65b562c930ac@grimberg.me>


> Since the data is coming in the form of an sgl, the reserved bits that the spec defines are not really reserved.
> I would expect that the spec will not mark the second byte of connect cmd as reserved
> (These reserved bits are not cleared to 0h)

I tend to agree, connect payload can and does come in a form of SGL, so
it appears that PSDT is required also for connect...


From sagi at grimberg.me  Thu Jan 14 16:13:05 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Thu, 14 Jan 2021 13:13:05 -0800
Subject: [PATCH] nvme: reject the ns when the block size is smaller than a
 sector
In-Reply-To: <20210114174311.GB31188@lst.de>
References: <20210113160621.98615-1-fengli@smartx.com>
 <SN4PR0401MB35985C08E5FFCDF0F5817A9D9BA90@SN4PR0401MB3598.namprd04.prod.outlook.com>
 <87698545-de26-c0ca-01e9-4dc2ddcacc80@grimberg.me>
 <20210114174311.GB31188@lst.de>
Message-ID: <74a92460-d681-8ec6-9df1-e33a5530160a@grimberg.me>


>>> But this only catches a physical block size < 512 for NVMe, not any other block device.
>>>
>>> Please fix it for the general case in blk_queue_physical_block_size().
>>
>> We actually call that later and would probably be better to check here..
> 
> We had a series for that a short while ago that got lost.

What was it called?


From sagi at grimberg.me  Thu Jan 14 16:15:23 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Thu, 14 Jan 2021 13:15:23 -0800
Subject: [PATCH 0/3 RESEND] few simple cleanups for nvme-tcp host
Message-ID: <20210114211526.86946-1-sagi@grimberg.me>

No real bug fix here, but some useful cleanups.

Sagi Grimberg (3):
  nvme-tcp: fix wrong setting of request iov_iter
  nvme-tcp: get rid of unused helper function
  nvme-tcp: pass multipage bvec to request iov_iter

 drivers/nvme/host/tcp.c | 25 +++++++++++--------------
 1 file changed, 11 insertions(+), 14 deletions(-)

-- 
2.25.1



From sagi at grimberg.me  Thu Jan 14 16:15:24 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Thu, 14 Jan 2021 13:15:24 -0800
Subject: [PATCH 1/3] nvme-tcp: fix wrong setting of request iov_iter
In-Reply-To: <20210114211526.86946-1-sagi@grimberg.me>
References: <20210114211526.86946-1-sagi@grimberg.me>
Message-ID: <20210114211526.86946-2-sagi@grimberg.me>

We might set the iov_iter direction wrong, which is
harmless for this use-case, but get it right.
Also this makes the code slightly cleaner.

Signed-off-by: Sagi Grimberg <sagi at grimberg.me>
---
 drivers/nvme/host/tcp.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 216619926563..acf41f50a9dd 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -982,7 +982,6 @@ static int nvme_tcp_try_send_cmd_pdu(struct nvme_tcp_request *req)
 			req->state = NVME_TCP_SEND_DATA;
 			if (queue->data_digest)
 				crypto_ahash_init(queue->snd_hash);
-			nvme_tcp_init_iter(req, WRITE);
 		} else {
 			nvme_tcp_done_send_req(queue);
 		}
@@ -1015,8 +1014,6 @@ static int nvme_tcp_try_send_data_pdu(struct nvme_tcp_request *req)
 		req->state = NVME_TCP_SEND_DATA;
 		if (queue->data_digest)
 			crypto_ahash_init(queue->snd_hash);
-		if (!req->data_sent)
-			nvme_tcp_init_iter(req, WRITE);
 		return 1;
 	}
 	req->offset += ret;
@@ -2262,12 +2259,12 @@ static blk_status_t nvme_tcp_setup_cmd_pdu(struct nvme_ns *ns,
 	req->data_len = blk_rq_nr_phys_segments(rq) ?
 				blk_rq_payload_bytes(rq) : 0;
 	req->curr_bio = rq->bio;
+	if (req->curr_bio)
+		nvme_tcp_init_iter(req, rq_data_dir(rq));
 
 	if (rq_data_dir(rq) == WRITE &&
 	    req->data_len <= nvme_tcp_inline_data_size(queue))
 		req->pdu_len = req->data_len;
-	else if (req->curr_bio)
-		nvme_tcp_init_iter(req, READ);
 
 	pdu->hdr.type = nvme_tcp_cmd;
 	pdu->hdr.flags = 0;
-- 
2.25.1



From sagi at grimberg.me  Thu Jan 14 16:15:25 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Thu, 14 Jan 2021 13:15:25 -0800
Subject: [PATCH 2/3] nvme-tcp: get rid of unused helper function
In-Reply-To: <20210114211526.86946-1-sagi@grimberg.me>
References: <20210114211526.86946-1-sagi@grimberg.me>
Message-ID: <20210114211526.86946-3-sagi@grimberg.me>

Signed-off-by: Sagi Grimberg <sagi at grimberg.me>
---
 drivers/nvme/host/tcp.c | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index acf41f50a9dd..0a738ba34aca 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -205,11 +205,6 @@ static inline size_t nvme_tcp_req_cur_length(struct nvme_tcp_request *req)
 			req->pdu_len - req->pdu_sent);
 }
 
-static inline size_t nvme_tcp_req_offset(struct nvme_tcp_request *req)
-{
-	return req->iter.iov_offset;
-}
-
 static inline size_t nvme_tcp_pdu_data_left(struct nvme_tcp_request *req)
 {
 	return rq_data_dir(blk_mq_rq_from_pdu(req)) == WRITE ?
-- 
2.25.1



From sagi at grimberg.me  Thu Jan 14 16:15:26 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Thu, 14 Jan 2021 13:15:26 -0800
Subject: [PATCH 3/3] nvme-tcp: pass multipage bvec to request iov_iter
In-Reply-To: <20210114211526.86946-1-sagi@grimberg.me>
References: <20210114211526.86946-1-sagi@grimberg.me>
Message-ID: <20210114211526.86946-4-sagi@grimberg.me>

iov_iter uses the right helpers so we should be able
to pass in a multipage bvec. Right now the iov_iter is
initialized with more segments that it needs which doesn't
fail because the iov_iter is capped by byte count, but it
is better to use a full multipage bvec iter.

Signed-off-by: Sagi Grimberg <sagi at grimberg.me>
---
 drivers/nvme/host/tcp.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 0a738ba34aca..4f8936751aa3 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -223,24 +223,29 @@ static void nvme_tcp_init_iter(struct nvme_tcp_request *req,
 	struct request *rq = blk_mq_rq_from_pdu(req);
 	struct bio_vec *vec;
 	unsigned int size;
-	int nsegs;
+	int nr_bvec;
 	size_t offset;
 
 	if (rq->rq_flags & RQF_SPECIAL_PAYLOAD) {
 		vec = &rq->special_vec;
-		nsegs = 1;
+		nr_bvec = 1;
 		size = blk_rq_payload_bytes(rq);
 		offset = 0;
 	} else {
 		struct bio *bio = req->curr_bio;
+		struct bvec_iter bi;
+		struct bio_vec bv;
 
 		vec = __bvec_iter_bvec(bio->bi_io_vec, bio->bi_iter);
-		nsegs = bio_segments(bio);
+		nr_bvec = 0;
+		bio_for_each_bvec(bv, bio, bi) {
+			nr_bvec++;
+		}
 		size = bio->bi_iter.bi_size;
 		offset = bio->bi_iter.bi_bvec_done;
 	}
 
-	iov_iter_bvec(&req->iter, dir, vec, nsegs, size);
+	iov_iter_bvec(&req->iter, dir, vec, nr_bvec, size);
 	req->iter.iov_offset = offset;
 }
 
-- 
2.25.1



From sagi at grimberg.me  Thu Jan 14 16:18:14 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Thu, 14 Jan 2021 13:18:14 -0800
Subject: [PATCH] nvme-tcp: fix a segmentation fault during io parsing error
In-Reply-To: <DM6PR19MB401194016A086DDF8A82C554EFA80@DM6PR19MB4011.namprd19.prod.outlook.com>
References: <20210113115152.69692-1-elad.grupi@dell.com>
 <ad9f038b-9920-21da-755c-85f4e2228a22@grimberg.me>
 <DM6PR19MB401194016A086DDF8A82C554EFA80@DM6PR19MB4011.namprd19.prod.outlook.com>
Message-ID: <f5b8dbc2-7960-894e-47ea-b18665536e70@grimberg.me>


> Thank you Sagi,
> 
> I will submit a new patch with a comment as requested.

Thanks.

> The patch you sent did not solve that issue, I submitted some comments on the relevant thread.

This was a silly typo, did you check if it addressed your issue when
you applied the needed change?

There are stuff there that I think we need to use for sorting out other
issues where your bug report is the trigger for this.


From sagi at grimberg.me  Thu Jan 14 16:25:28 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Thu, 14 Jan 2021 13:25:28 -0800
Subject: [PATCH v2 4/6] nvme-rdma: avoid IO error and repeated request
 completion
In-Reply-To: <7b12be41-0fcd-5a22-0e01-8cd4ac9cde5b@huawei.com>
References: <20210107033149.15701-1-lengchao@huawei.com>
 <20210107033149.15701-5-lengchao@huawei.com>
 <07e41b4f-914a-11e8-5638-e2d6408feb3f@grimberg.me>
 <7b12be41-0fcd-5a22-0e01-8cd4ac9cde5b@huawei.com>
Message-ID: <a3404c7d-ccc8-0d55-d4a8-fc15107c90e6@grimberg.me>


>>> When a request is queued failed, blk_status_t is directly returned
>>> to the blk-mq. If blk_status_t is not BLK_STS_RESOURCE,
>>> BLK_STS_DEV_RESOURCE, BLK_STS_ZONE_RESOURCE, blk-mq call
>>> blk_mq_end_request to complete the request with BLK_STS_IOERR.
>>> In two scenarios, the request should be retried and may succeed.
>>> First, if work with nvme multipath, the request may be retried
>>> successfully in another path, because the error is probably related to
>>> the path. Second, if work without multipath software, the request may
>>> be retried successfully after error recovery.
>>> If the request is complete with BLK_STS_IOERR in 
>>> blk_mq_dispatch_rq_list.
>>> The state of request may be changed to MQ_RQ_IN_FLIGHT. If free the
>>> request asynchronously such as in nvme_submit_user_cmd, in extreme
>>> scenario the request will be repeated freed in tear down.
>>> If a non-resource error occurs in queue_rq, should directly call
>>> nvme_complete_rq to complete request and set the state of request to
>>> MQ_RQ_COMPLETE. nvme_complete_rq will decide to retry, fail over or end
>>> the request.
>>>
>>> Signed-off-by: Chao Leng <lengchao at huawei.com>
>>> ---
>>> ? drivers/nvme/host/rdma.c | 2 +-
>>> ? 1 file changed, 1 insertion(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
>>> index df9f6f4549f1..4a89bf44ecdc 100644
>>> --- a/drivers/nvme/host/rdma.c
>>> +++ b/drivers/nvme/host/rdma.c
>>> @@ -2093,7 +2093,7 @@ static blk_status_t nvme_rdma_queue_rq(struct 
>>> blk_mq_hw_ctx *hctx,
>>> ? unmap_qe:
>>> ????? ib_dma_unmap_single(dev, req->sqe.dma, sizeof(struct 
>>> nvme_command),
>>> ????????????????? DMA_TO_DEVICE);
>>> -??? return ret;
>>> +??? return nvme_try_complete_failed_req(rq, ret);
>>
>> I don't understand this. There are errors that may not be related to
>> anything that is pathing related (sw bug, memory leak, mapping error,
>> etc, etc) why should we return this one-shot error?
> Although fail over retry is not required, if we return the error to
> blk-mq, a low probability crash may happen. because blk-mq do not set
> the state of request to MQ_RQ_COMPLETE before complete the request,
> the request may be freed asynchronously such as in nvme_submit_user_cmd.
> If race with error recovery, request double completion may happens.

Then fix that, don't work around it.

> 
> So we can not return the error to blk-mq if the blk_status_t is not
> BLK_STS_RESOURCE, BLK_STS_DEV_RESOURCE, BLK_STS_ZONE_RESOURCE.

This is not something we should be handling in nvme. block drivers
should be able to fail queue_rq, and this all should live in the
block layer.


From Elad.Grupi at dell.com  Thu Jan 14 16:41:58 2021
From: Elad.Grupi at dell.com (Grupi, Elad)
Date: Thu, 14 Jan 2021 21:41:58 +0000
Subject: [PATCH] nvme-tcp: fix a segmentation fault during io parsing error
In-Reply-To: <f5b8dbc2-7960-894e-47ea-b18665536e70@grimberg.me>
References: <20210113115152.69692-1-elad.grupi@dell.com>
 <ad9f038b-9920-21da-755c-85f4e2228a22@grimberg.me>
 <DM6PR19MB401194016A086DDF8A82C554EFA80@DM6PR19MB4011.namprd19.prod.outlook.com>
 <f5b8dbc2-7960-894e-47ea-b18665536e70@grimberg.me>
Message-ID: <DM6PR19MB4011A4116FAB37BEC28BBC91EFA80@DM6PR19MB4011.namprd19.prod.outlook.com>

> This was a silly typo, did you check if it addressed your issue when you applied the needed change?

Yes. We applied the needed change before testing your patch, but still had kernel panic on recv flow when we had unread inline data on the socket.

> There are stuff there that I think we need to use for sorting out other issues where your bug report is the trigger for this.

I agree, changes looks good. 

-----Original Message-----
From: Sagi Grimberg <sagi at grimberg.me> 
Sent: Thursday, 14 January 2021 23:18
To: Grupi, Elad; linux-nvme at lists.infradead.org
Subject: Re: [PATCH] nvme-tcp: fix a segmentation fault during io parsing error


[EXTERNAL EMAIL] 


> Thank you Sagi,
> 
> I will submit a new patch with a comment as requested.

Thanks.

> The patch you sent did not solve that issue, I submitted some comments on the relevant thread.

This was a silly typo, did you check if it addressed your issue when you applied the needed change?

There are stuff there that I think we need to use for sorting out other issues where your bug report is the trigger for this.

From Frederick.Knight at netapp.com  Thu Jan 14 17:59:09 2021
From: Frederick.Knight at netapp.com (Knight, Frederick)
Date: Thu, 14 Jan 2021 22:59:09 +0000
Subject: [PATCH] nvme-core: update NS Attr Changed AEN handling for ANA
 group
In-Reply-To: <eb84db43-5e63-19b4-cdb9-53f52d1c45e8@grimberg.me>
References: <20201209155321.GA31729@redsun51.ssa.fujisawa.hgst.com>
 <b9c9e5f9-a447-2a2e-b687-304dd8f3d2b2@suse.de>
 <20201209161911.GA31836@redsun51.ssa.fujisawa.hgst.com>
 <66bad47c-0cd3-8461-3629-146778f15059@suse.de>
 <20201209173936.GA31971@redsun51.ssa.fujisawa.hgst.com>
 <20201209174718.GA19512@lst.de>
 <DM5PR0601MB3624722C4C00B5A7EDB7E6A0F1CC0@DM5PR0601MB3624.namprd06.prod.outlook.com>
 <20201209213437.GA3682670@dhcp-10-100-145-180.wdc.com>
 <20201210085111.GA15999@lst.de>
 <baa8c2e6-1376-1cad-4c84-1129bd80d4ca@suse.de>
 <20201210133418.GA3645@redsun51.ssa.fujisawa.hgst.com>
 <eb84db43-5e63-19b4-cdb9-53f52d1c45e8@grimberg.me>
Message-ID: <DM5PR0601MB3624BB4004C273271F30052AF1A80@DM5PR0601MB3624.namprd06.prod.outlook.com>

Attached is the proposed clarification.  This has had ZERO review time in the NVMe committee.  So just FYI at this point.

Feel free to share thoughts.

	Fred

-----Original Message-----
From: Sagi Grimberg <sagi at grimberg.me> 
Sent: Wednesday, January 13, 2021 10:09 PM
To: Keith Busch <kbusch at kernel.org>; Hannes Reinecke <hare at suse.de>
Cc: hch at lst.de; Knight, Frederick <Frederick.Knight at netapp.com>; Meneghini, John <John.Meneghini at netapp.com>; George, Martin <Martin.George at netapp.com>; linux-nvme at lists.infradead.org; Hannes Reinecke <hare at suse.com>
Subject: Re: [PATCH] nvme-core: update NS Attr Changed AEN handling for ANA group

NetApp Security WARNING: This is an external email. Do not click links or open attachments unless you recognize the sender and know the content is safe.




Hey all,

Joining late to the discussion, ramping up on an old old backlog...

>>> On Wed, Dec 09, 2020 at 01:34:37PM -0800, Keith Busch wrote:
>>>> Linux hosts currently want an ANA AEN anytime the host needs to 
>>>> refresh the ANA log. That includes any condition that adds groups 
>>>> that didn't exist from the host's previous reading.
>>>>
>>>> If the Namespace Attach occurs to an ANA group the host already 
>>>> knows about, then you don't need to send an ANA AEN because there's 
>>>> nothing new in the log that the host requires. You just need to 
>>>> send the NS Notify AEN.
>>>>
>>>> But if a side effect of attaching a namespace results in a new ANA 
>>>> group becoming visible to the host, then that group creation is 
>>>> considered a separate event, so the host wants both AENs. I believe 
>>>> this is where Christoph is trying to steer the interpretation and the text.
>>>
>>> Exactly.  Although as Hannes pointed out, this language:
>>>
>>>     If, for an ANA Group, there are no namespaces attached to the
>>>     controller processing the command, then no ANA Group Descriptor is
>>>     returned for that ANA Group (i.e., an ANA Group Descriptor is returned
>>>     only if that ANA Group contains namespaces that are attached to the
>>>     controller processing the command.
>>>
>>> creates a bit of a chicken an egg problem in that case of a newly 
>>> attached namespace that is the first one referencing an ANA group.

FWIW, the subsystems I'm familiar with are sending both events in this case and the interpretation of this paragraph was that although the ANA group existed since day-0, the host was never informed about it, so just like lots of other internal resources, it doesn't exist from an interface perspective.

The alternative would have been to tell the host about every ANA group that the subsystem is managing, which could be a very large number and just creates a churn of completely useless huge log pages.

>> Yes, this was what I tried to outline.
>>
>> Personally I don't mind whether the controller is required to send an 
>> ANA change AEN together with the NS change AEN.
>> Requiring both will pose an ordering issue (as on fabrics we can't 
>> control the completion ordering), so effectively we'll have to 
>> implement handling for AENs arriving in any order.
>
> I was thinking more about this, and it's actually not a problem based 
> on how the controller is allowed to send AEN completions:
>
>    When the controller posts a completion queue entry for an outstanding
>    Asynchronous Event Request command and thus reports an asynchronous
>    event, subsequent events of that event type are automatically masked by
>    the controller until the host clears that event.
>
> These are both "Notice" event types, so the controller is not allowed 
> to send both at the same time. The host must acknowledge the first 
> before the second can be seen, so we can enforce a deterministic sequence.

Well that is easy today because there is only one aen at a time...

> And while it may make sense if the first event seen is the ANA one 
> before the NS, it doesn't look like Linux cares if we observe them the 
> other way around. The only thing the driver needs to do is synchronize 
> the work queues for each event.

Yes, the order doesn't matter and we should keep it that way...

>> But I'm also fine with just getting one AEN; the patch will solve 
>> that situation just fine.
>
> I'm also okay with that patch, too.

I would actually be in favor of this patch, would be nice to skip sending duplicate events for this.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: NVMe - NVMe 1.4 ECN-008 2021.01.13.docx
Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document
Size: 81284 bytes
Desc: NVMe - NVMe 1.4 ECN-008 2021.01.13.docx
URL: <http://lists.infradead.org/pipermail/linux-nvme/attachments/20210114/dd699af9/attachment-0001.docx>

From kbusch at kernel.org  Thu Jan 14 18:05:27 2021
From: kbusch at kernel.org (Keith Busch)
Date: Thu, 14 Jan 2021 15:05:27 -0800
Subject: [PATCH V4 1/4] nvmet: set right status on error in id-ns handler
In-Reply-To: <20210114013354.33946-2-chaitanya.kulkarni@wdc.com>
References: <20210114013354.33946-1-chaitanya.kulkarni@wdc.com>
 <20210114013354.33946-2-chaitanya.kulkarni@wdc.com>
Message-ID: <20210114230527.GD1511902@dhcp-10-100-145-180.wdc.com>

Patch looks good.

Reviewed-by: Keith Busch <kbusch at kernel.org>


From kbusch at kernel.org  Thu Jan 14 18:16:14 2021
From: kbusch at kernel.org (Keith Busch)
Date: Thu, 14 Jan 2021 15:16:14 -0800
Subject: [PATCH] nvme-core: update NS Attr Changed AEN handling for ANA
 group
In-Reply-To: <DM5PR0601MB3624BB4004C273271F30052AF1A80@DM5PR0601MB3624.namprd06.prod.outlook.com>
References: <66bad47c-0cd3-8461-3629-146778f15059@suse.de>
 <20201209173936.GA31971@redsun51.ssa.fujisawa.hgst.com>
 <20201209174718.GA19512@lst.de>
 <DM5PR0601MB3624722C4C00B5A7EDB7E6A0F1CC0@DM5PR0601MB3624.namprd06.prod.outlook.com>
 <20201209213437.GA3682670@dhcp-10-100-145-180.wdc.com>
 <20201210085111.GA15999@lst.de>
 <baa8c2e6-1376-1cad-4c84-1129bd80d4ca@suse.de>
 <20201210133418.GA3645@redsun51.ssa.fujisawa.hgst.com>
 <eb84db43-5e63-19b4-cdb9-53f52d1c45e8@grimberg.me>
 <DM5PR0601MB3624BB4004C273271F30052AF1A80@DM5PR0601MB3624.namprd06.prod.outlook.com>
Message-ID: <20210114231614.GE1511902@dhcp-10-100-145-180.wdc.com>

On Thu, Jan 14, 2021 at 10:59:09PM +0000, Knight, Frederick wrote:
> Attached is the proposed clarification.  This has had ZERO review time in the NVMe committee.  So just FYI at this point.
> 
> Feel free to share thoughts.

The ECN retains the text that no new ANA event shall be sent if "the
change is due to the creation of a namespace", which seems odd to
continue pointing out given that namespace creation doesn't alter the
ANA log.

Also, if you're going to use this ECN to ensure namespace attachment to
a new ANA group suppresses the ANA event, could you also update section
8.20.3.6 to change: 

  c) upon entry to the following ANA states:

to something like

  c) upon entry to the following ANA states except if the state entry
     occurs as a result of a namespace attachment:

Just so everyone is consistent with the "exceptions".


From revanth.rajashekar at intel.com  Thu Jan 14 20:55:07 2021
From: revanth.rajashekar at intel.com (Revanth Rajashekar)
Date: Thu, 14 Jan 2021 18:55:07 -0700
Subject: [PATCH v3] nvme: Check the PRINFO bit and the Metadata size before
 deciding the host buffer length
Message-ID: <20210115015507.45615-1-revanth.rajashekar@intel.com>

According to NVMe spec v1.4, section 8.3.1, the PRINFO bit and
the metadata size play a vital role in deteriming the host buffer size.

If PRIFNO bit is set and MS==8, the host doesn't add the metadata buffer,
instead the controller adds it.

Changes from v2:
1. Use sizeof(struct t10_pi_tuple) to check against MS.
2. Use if-else statements to set the meta_len and metadata

Changes from v1:
1. Remove the definition 'NVME_PRINFO_CTRL_BIT'
2. Remove variable 'control'
3. Remove test_bit and check the bit with the CPU arch's native endianness

Signed-off-by: Revanth Rajashekar <revanth.rajashekar at intel.com>
---
 drivers/nvme/host/core.c | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index f320273fc672..ec9f8f686460 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -1543,8 +1543,21 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
 	}

 	length = (io.nblocks + 1) << ns->lba_shift;
-	meta_len = (io.nblocks + 1) * ns->ms;
-	metadata = nvme_to_user_ptr(io.metadata);
+
+	if ((io.control & NVME_RW_PRINFO_PRACT) &&
+		ns->ms == sizeof(struct t10_pi_tuple)) {
+		/*
+		 * Protection information is stripped/inserted by the
+		 * controller.
+		 */
+		if (nvme_to_user_ptr(io.metadata))
+			return -EINVAL;
+		meta_len = 0;
+		metadata = NULL;
+	} else {
+		meta_len = (io.nblocks + 1) * ns->ms;
+		metadata = nvme_to_user_ptr(io.metadata);
+	}

 	if (ns->features & NVME_NS_EXT_LBAS) {
 		length += meta_len;
--
2.17.1



From lengchao at huawei.com  Thu Jan 14 21:16:49 2021
From: lengchao at huawei.com (Chao Leng)
Date: Fri, 15 Jan 2021 10:16:49 +0800
Subject: [PATCH V3 2/3] nvme: introduce acre flag in nvme_ctrl
In-Reply-To: <20210114133110.20779-3-minwoo.im.dev@gmail.com>
References: <20210114133110.20779-1-minwoo.im.dev@gmail.com>
 <20210114133110.20779-3-minwoo.im.dev@gmail.com>
Message-ID: <9bd3a29a-6033-13bb-5957-28560ba91b9c@huawei.com>

Reviewed-by: Chao Leng <lengchao at huawei.com>

On 2021/1/14 21:31, Minwoo Im wrote:
> Advanced Command Retry Enable (ACRE) flag is added in nvme_ctrl
> instance to indicate that Set Features for Host Behavior Support with
> ACRE enabled is whether successfully done or not during reset_work.
> 
> This flag will be used to decide to retry commands that fail or not in
> the followed patch.
> 
> Signed-off-by: Minwoo Im <minwoo.im.dev at gmail.com>
> ---
>   drivers/nvme/host/core.c | 6 ++++++
>   drivers/nvme/host/nvme.h | 1 +
>   2 files changed, 7 insertions(+)
> 
> diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
> index a8cee380b3c0..a286e3422c61 100644
> --- a/drivers/nvme/host/core.c
> +++ b/drivers/nvme/host/core.c
> @@ -2498,6 +2498,8 @@ static int nvme_configure_acre(struct nvme_ctrl *ctrl)
>   	struct nvme_feat_host_behavior *host;
>   	int ret;
>   
> +	ctrl->acre = false;
> +
>   	/* Don't bother enabling the feature if retry delay is not reported */
>   	if (!ctrl->crdt[0] && !ctrl->crdt[1] && !ctrl->crdt[2])
>   		return 0;
> @@ -2509,6 +2511,10 @@ static int nvme_configure_acre(struct nvme_ctrl *ctrl)
>   	host->acre = NVME_ENABLE_ACRE;
>   	ret = nvme_set_features(ctrl, NVME_FEAT_HOST_BEHAVIOR, 0,
>   				host, sizeof(*host), NULL);
> +
> +	if (!ret)
> +		ctrl->acre = true;
> +
>   	kfree(host);
>   	return ret;
>   }
> diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
> index 88a6b97247f5..db8b45e8ffde 100644
> --- a/drivers/nvme/host/nvme.h
> +++ b/drivers/nvme/host/nvme.h
> @@ -270,6 +270,7 @@ struct nvme_ctrl {
>   #ifdef CONFIG_BLK_DEV_ZONED
>   	u32 max_zone_append;
>   #endif
> +	bool acre;
>   	u16 crdt[3];
>   	u16 oncs;
>   	u16 oacs;
> 


From lengchao at huawei.com  Thu Jan 14 21:17:01 2021
From: lengchao at huawei.com (Chao Leng)
Date: Fri, 15 Jan 2021 10:17:01 +0800
Subject: [PATCH V3 3/3] nvme: retry commands based on ACRE flag
In-Reply-To: <20210114133110.20779-4-minwoo.im.dev@gmail.com>
References: <20210114133110.20779-1-minwoo.im.dev@gmail.com>
 <20210114133110.20779-4-minwoo.im.dev@gmail.com>
Message-ID: <6b01201e-fee7-db30-247e-444881f4cbed@huawei.com>

Reviewed-by: Chao Leng <lengchao at huawei.com>

On 2021/1/14 21:31, Minwoo Im wrote:
> Allow nvme_decide_disposition() to retry commands with error by checking
> Advanced Command Retry Enable (ACRE) flag of controller first than
> REQ_FAILFAST_* cmd_flags.  But, we just can't allow all command failures
> to be retried due to reasons like connecting may take too long due to
> the retries.  This patch only allows non-host path error commands to be
> retried.
> 
> Cc: Chao Leng <lengchao at huawei.com>
> Cc: Sagi Grimberg <sagi at grimberg.me>
> Cc: Keith Busch <kbusch at kernel.org>
> Signed-off-by: Minwoo Im <minwoo.im.dev at gmail.com>
> ---
>   drivers/nvme/host/core.c | 10 ++++++++--
>   1 file changed, 8 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
> index a286e3422c61..e4f7c49c2f39 100644
> --- a/drivers/nvme/host/core.c
> +++ b/drivers/nvme/host/core.c
> @@ -303,8 +303,7 @@ static inline enum nvme_disposition nvme_decide_disposition(struct request *req)
>   	if (likely(nvme_req(req)->status == 0))
>   		return COMPLETE;
>   
> -	if (blk_noretry_request(req) ||
> -	    (nvme_req(req)->status & NVME_SC_DNR) ||
> +	if ((nvme_req(req)->status & NVME_SC_DNR) ||
>   	    nvme_req(req)->retries >= nvme_max_retries)
>   		return COMPLETE;
>   
> @@ -317,6 +316,13 @@ static inline enum nvme_disposition nvme_decide_disposition(struct request *req)
>   			return COMPLETE;
>   	}
>   
> +	if (nvme_req(req)->ctrl->acre &&
> +	    !nvme_is_path_error(nvme_req(req)->status) &&
> +	    !blk_queue_dying(req->q))
> +		return RETRY;
> +	else if (blk_noretry_request(req))
> +		return COMPLETE;
> +
>   	return RETRY;
>   }
>   
> 


From axboe at kernel.dk  Thu Jan 14 21:48:07 2021
From: axboe at kernel.dk (Jens Axboe)
Date: Thu, 14 Jan 2021 19:48:07 -0700
Subject: [GIT PULL] nvme fixes for 5.11
In-Reply-To: <YACbrIes4r8Qa1mA@infradead.org>
References: <YACbrIes4r8Qa1mA@infradead.org>
Message-ID: <ac34b82a-1391-7ba9-834c-daabaf65d125@kernel.dk>

On Thu, Jan 14, 2021 at 12:30 PM Christoph Hellwig <hch at infradead.org> wrote:
>
> The following changes since commit 5342fd4255021ef0c4ce7be52eea1c4ebda11c63:
>
>   bcache: set bcache device into read-only mode for BCH_FEATURE_INCOMPAT_OBSO_LARGE_BUCKET (2021-01-09 09:21:03 -0700)
>
> are available in the Git repository at:
>
>   git://git.infradead.org/nvme.git tags/nvme-5.11-2021-01-14

Pulled, thanks.

-- 
Jens Axboe



From lengchao at huawei.com  Thu Jan 14 21:53:41 2021
From: lengchao at huawei.com (Chao Leng)
Date: Fri, 15 Jan 2021 10:53:41 +0800
Subject: [PATCH v2 4/6] nvme-rdma: avoid IO error and repeated request
 completion
In-Reply-To: <a3404c7d-ccc8-0d55-d4a8-fc15107c90e6@grimberg.me>
References: <20210107033149.15701-1-lengchao@huawei.com>
 <20210107033149.15701-5-lengchao@huawei.com>
 <07e41b4f-914a-11e8-5638-e2d6408feb3f@grimberg.me>
 <7b12be41-0fcd-5a22-0e01-8cd4ac9cde5b@huawei.com>
 <a3404c7d-ccc8-0d55-d4a8-fc15107c90e6@grimberg.me>
Message-ID: <695b6839-5333-c342-2189-d7aaeba797a7@huawei.com>



On 2021/1/15 5:25, Sagi Grimberg wrote:
> 
>>>> When a request is queued failed, blk_status_t is directly returned
>>>> to the blk-mq. If blk_status_t is not BLK_STS_RESOURCE,
>>>> BLK_STS_DEV_RESOURCE, BLK_STS_ZONE_RESOURCE, blk-mq call
>>>> blk_mq_end_request to complete the request with BLK_STS_IOERR.
>>>> In two scenarios, the request should be retried and may succeed.
>>>> First, if work with nvme multipath, the request may be retried
>>>> successfully in another path, because the error is probably related to
>>>> the path. Second, if work without multipath software, the request may
>>>> be retried successfully after error recovery.
>>>> If the request is complete with BLK_STS_IOERR in blk_mq_dispatch_rq_list.
>>>> The state of request may be changed to MQ_RQ_IN_FLIGHT. If free the
>>>> request asynchronously such as in nvme_submit_user_cmd, in extreme
>>>> scenario the request will be repeated freed in tear down.
>>>> If a non-resource error occurs in queue_rq, should directly call
>>>> nvme_complete_rq to complete request and set the state of request to
>>>> MQ_RQ_COMPLETE. nvme_complete_rq will decide to retry, fail over or end
>>>> the request.
>>>>
>>>> Signed-off-by: Chao Leng <lengchao at huawei.com>
>>>> ---
>>>> ? drivers/nvme/host/rdma.c | 2 +-
>>>> ? 1 file changed, 1 insertion(+), 1 deletion(-)
>>>>
>>>> diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
>>>> index df9f6f4549f1..4a89bf44ecdc 100644
>>>> --- a/drivers/nvme/host/rdma.c
>>>> +++ b/drivers/nvme/host/rdma.c
>>>> @@ -2093,7 +2093,7 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
>>>> ? unmap_qe:
>>>> ????? ib_dma_unmap_single(dev, req->sqe.dma, sizeof(struct nvme_command),
>>>> ????????????????? DMA_TO_DEVICE);
>>>> -??? return ret;
>>>> +??? return nvme_try_complete_failed_req(rq, ret);
>>>
>>> I don't understand this. There are errors that may not be related to
>>> anything that is pathing related (sw bug, memory leak, mapping error,
>>> etc, etc) why should we return this one-shot error?
>> Although fail over retry is not required, if we return the error to
>> blk-mq, a low probability crash may happen. because blk-mq do not set
>> the state of request to MQ_RQ_COMPLETE before complete the request,
>> the request may be freed asynchronously such as in nvme_submit_user_cmd.
>> If race with error recovery, request double completion may happens.
> 
> Then fix that, don't work around it.
I'm not trying to work around it. The purpose of this is to solve
the problem of nvme native multipathing at the same time.
> 
>>
>> So we can not return the error to blk-mq if the blk_status_t is not
>> BLK_STS_RESOURCE, BLK_STS_DEV_RESOURCE, BLK_STS_ZONE_RESOURCE.
> 
> This is not something we should be handling in nvme. block drivers
> should be able to fail queue_rq, and this all should live in the
> block layer.
Of course, it is also an idea to repair the block drivers directly.
However, block layer is unaware of nvme native multipathing, will cause
the request return error which should be avoided.
The scenario: use two HBAs for nvme native multipath, and then one HBA
fault, the blk_status_t of queue_rq is BLK_STS_IOERR, blk-mq will call
blk_mq_end_request to complete the request which bypass name native
multipath. We expect the request fail over to normal HBA, but the request
is directly completed with BLK_STS_IOERR.
The two scenarios can be fixed by directly completing the request in queue_rq.

> .


From fengli at smartx.com  Thu Jan 14 22:30:06 2021
From: fengli at smartx.com (Li Feng)
Date: Fri, 15 Jan 2021 11:30:06 +0800
Subject: [PATCH] nvme: reject the ns when the block size is smaller than a
 sector
In-Reply-To: <20210114174311.GB31188@lst.de>
References: <20210113160621.98615-1-fengli@smartx.com>
 <SN4PR0401MB35985C08E5FFCDF0F5817A9D9BA90@SN4PR0401MB3598.namprd04.prod.outlook.com>
 <87698545-de26-c0ca-01e9-4dc2ddcacc80@grimberg.me>
 <20210114174311.GB31188@lst.de>
Message-ID: <CAHckoCzhJVAWFSYeCAMHZ+fVqzv_1XxvM97QmvCESnEcc5AQuQ@mail.gmail.com>

Christoph Hellwig <hch at lst.de> ?2021?1?15??? ??1:43???
>
> On Wed, Jan 13, 2021 at 02:12:59PM -0800, Sagi Grimberg wrote:
> >> But this only catches a physical block size < 512 for NVMe, not any other block device.
> >>
> >> Please fix it for the general case in blk_queue_physical_block_size().
> >
> > We actually call that later and would probably be better to check here..
>
> We had a series for that a short while ago that got lost.
Where is the series? Or could you advise on how to fix this issue is acceptable?
This issue will generate an oops, check it here:
https://lkml.org/lkml/2021/1/12/1064

Thanks,
Feng Li


From its at irrelevant.dk  Fri Jan 15 01:12:14 2021
From: its at irrelevant.dk (Klaus Jensen)
Date: Fri, 15 Jan 2021 07:12:14 +0100
Subject: [PATCH] nvme: allow use of cmb on v1.4 controllers
In-Reply-To: <20210114173313.GA31028@lst.de>
References: <20210114132441.193782-1-its@irrelevant.dk>
 <20210114173313.GA31028@lst.de>
Message-ID: <YAEyPrRkvJiRaoTr@apples.localdomain>

On Jan 14 18:33, Christoph Hellwig wrote:
> On Thu, Jan 14, 2021 at 02:24:41PM +0100, Klaus Jensen wrote:
> > From: Klaus Jensen <k.jensen at samsung.com>
> > 
> > Since NVMe v1.4 the Controller Memory Buffer must be explicitly enabled
> > by the host.
> 
> Thanks, this has been on my TODO list for a while.
> 
> > +	vs = readl(dev->bar + NVME_REG_VS);
> > +
> > +	if (vs >= NVME_VS(1, 4, 0)) {
> > +		if (!NVME_CAP_CMBS(dev->ctrl.cap))
> > +			return;
> 
> We should not check the version here, but the presence of the new
> register so that controllers claiming an older version complicance
> that implement the new scheme are supported as well.
> 

Understood!

> Given that the old scheme is highly dangerous in virtualized enviroments
> we should also warn about it and eventually required an explicit opt-in
> to use it.
> 

Not completely sure what warning you'd want, so I'll leave it to you to
add an 'else dev_warn(...)'. :)

> > +	if (vs >= NVME_VS(1, 4, 0)) {
> > +		cmbmsc = pci_resource_start(pdev, bar);
> > +		cmbmsc |= (NVME_CMBMSC_CRE | NVME_CMBMSC_CMSE);
> > +
> > +		/*
> > +		 * Writing the low bits may cause the controller to check the
> > +		 * validity of the 52 bit controller base address in the CMBMSC
> > +		 * register, so write the high bits first.
> > +		 */
> > +		writel(cmbmsc >> 32, dev->bar + NVME_REG_CMBMSC + 4);
> > +		writel(cmbmsc, dev->bar + NVME_REG_CMBMSC);
> 
> I think we should just use writeq here, with the hilo wrapper for 32-bit
> platforms here.  The reason why NVMe has so avoided the 64-bit access
> is for buggy Apple controllers, but they are unlikely to implement CMB.

Right, I tried writeq, but on QEMU I observed two 4 byte writes in wrong
order anyway.

hi_lo_writeq looks good.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-nvme/attachments/20210115/00e1a2c2/attachment.sig>

From its at irrelevant.dk  Fri Jan 15 01:13:11 2021
From: its at irrelevant.dk (Klaus Jensen)
Date: Fri, 15 Jan 2021 07:13:11 +0100
Subject: [PATCH] nvme: allow use of cmb on v1.4 controllers
In-Reply-To: <20210114180600.GA1511435@dhcp-10-100-145-180.wdc.com>
References: <20210114132441.193782-1-its@irrelevant.dk>
 <20210114180600.GA1511435@dhcp-10-100-145-180.wdc.com>
Message-ID: <YAEyd5fNOa1/3gN2@apples.localdomain>

On Jan 14 10:06, Keith Busch wrote:
> On Thu, Jan 14, 2021 at 02:24:41PM +0100, Klaus Jensen wrote:
> > @@ -1795,6 +1796,15 @@ static void nvme_map_cmb(struct nvme_dev *dev)
> >  	if (dev->cmb_size)
> >  		return;
> >  
> > +	vs = readl(dev->bar + NVME_REG_VS);
> > +
> > +	if (vs >= NVME_VS(1, 4, 0)) {
> > +		if (!NVME_CAP_CMBS(dev->ctrl.cap))
> > +			return;
> > +
> > +		writel(NVME_CMBMSC_CRE, dev->bar + NVME_REG_CMBMSC);
> > +	}
> > +
> >  	dev->cmbsz = readl(dev->bar + NVME_REG_CMBSZ);
> >  	if (!dev->cmbsz)
> >  		return;
> > @@ -1805,6 +1815,19 @@ static void nvme_map_cmb(struct nvme_dev *dev)
> >  	bar = NVME_CMB_BIR(dev->cmbloc);
> >  	bar_size = pci_resource_len(pdev, bar);
> >  
> > +	if (vs >= NVME_VS(1, 4, 0)) {
> > +		cmbmsc = pci_resource_start(pdev, bar);
> 
> Shouldn't this have a '+ offset' in case the CMB doesn't start at the
> beginning of the bar?
> 


Of course, good catch!

> > +		cmbmsc |= (NVME_CMBMSC_CRE | NVME_CMBMSC_CMSE);
> > +
> > +		/*
> > +		 * Writing the low bits may cause the controller to check the
> > +		 * validity of the 52 bit controller base address in the CMBMSC
> > +		 * register, so write the high bits first.
> > +		 */
> > +		writel(cmbmsc >> 32, dev->bar + NVME_REG_CMBMSC + 4);
> > +		writel(cmbmsc, dev->bar + NVME_REG_CMBMSC);
> 
> hi_lo_writeq()?
> 

Ah, was looking for that...

> This should probably come after we've verified the '(offset > bar_size)'
> check below so that we're not enabling these capabilities before we know
> if they're within the BAR.
> 

Right.

> > +	}
> > +
> >  	if (offset > bar_size)
> >  		return;

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-nvme/attachments/20210115/2063665b/attachment.sig>

From its at irrelevant.dk  Fri Jan 15 01:30:46 2021
From: its at irrelevant.dk (Klaus Jensen)
Date: Fri, 15 Jan 2021 07:30:46 +0100
Subject: [PATCH v2] nvme: allow use of cmb on v1.4 controllers
Message-ID: <20210115063046.274495-1-its@irrelevant.dk>

From: Klaus Jensen <k.jensen at samsung.com>

Since NVMe v1.4 the Controller Memory Buffer must be explicitly enabled
by the host.

Signed-off-by: Klaus Jensen <k.jensen at samsung.com>
---
 drivers/nvme/host/pci.c | 13 ++++++++++++-
 include/linux/nvme.h    |  6 ++++++
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 50d9a20568a2..62eb83030a5a 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -23,6 +23,7 @@
 #include <linux/t10-pi.h>
 #include <linux/types.h>
 #include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/io-64-nonatomic-hi-lo.h>
 #include <linux/sed-opal.h>
 #include <linux/pci-p2pdma.h>
 
@@ -1787,7 +1788,7 @@ static u32 nvme_cmb_size(struct nvme_dev *dev)
 
 static void nvme_map_cmb(struct nvme_dev *dev)
 {
-	u64 size, offset;
+	u64 size, offset, cmbmsc;
 	resource_size_t bar_size;
 	struct pci_dev *pdev = to_pci_dev(dev->dev);
 	int bar;
@@ -1795,6 +1796,9 @@ static void nvme_map_cmb(struct nvme_dev *dev)
 	if (dev->cmb_size)
 		return;
 
+	if (NVME_CAP_CMBS(dev->ctrl.cap))
+		writel(NVME_CMBMSC_CRE, dev->bar + NVME_REG_CMBMSC);
+
 	dev->cmbsz = readl(dev->bar + NVME_REG_CMBSZ);
 	if (!dev->cmbsz)
 		return;
@@ -1808,6 +1812,13 @@ static void nvme_map_cmb(struct nvme_dev *dev)
 	if (offset > bar_size)
 		return;
 
+	if (NVME_CAP_CMBS(dev->ctrl.cap)) {
+		cmbmsc = pci_bus_address(pdev, bar) + offset;
+		cmbmsc |= (NVME_CMBMSC_CRE | NVME_CMBMSC_CMSE);
+
+		hi_lo_writeq(cmbmsc, dev->bar + NVME_REG_CMBMSC);
+	}
+
 	/*
 	 * Controllers may support a CMB size larger than their BAR,
 	 * for example, due to being behind a bridge. Reduce the CMB to
diff --git a/include/linux/nvme.h b/include/linux/nvme.h
index d92535997687..bfed36e342cc 100644
--- a/include/linux/nvme.h
+++ b/include/linux/nvme.h
@@ -116,6 +116,9 @@ enum {
 	NVME_REG_BPMBL	= 0x0048,	/* Boot Partition Memory Buffer
 					 * Location
 					 */
+	NVME_REG_CMBMSC = 0x0050,	/* Controller Memory Buffer Memory
+					 * Space Control
+					 */
 	NVME_REG_PMRCAP	= 0x0e00,	/* Persistent Memory Capabilities */
 	NVME_REG_PMRCTL	= 0x0e04,	/* Persistent Memory Region Control */
 	NVME_REG_PMRSTS	= 0x0e08,	/* Persistent Memory Region Status */
@@ -135,6 +138,7 @@ enum {
 #define NVME_CAP_CSS(cap)	(((cap) >> 37) & 0xff)
 #define NVME_CAP_MPSMIN(cap)	(((cap) >> 48) & 0xf)
 #define NVME_CAP_MPSMAX(cap)	(((cap) >> 52) & 0xf)
+#define NVME_CAP_CMBS(cap)	(((cap) >> 57) & 0x1)
 
 #define NVME_CMB_BIR(cmbloc)	((cmbloc) & 0x7)
 #define NVME_CMB_OFST(cmbloc)	(((cmbloc) >> 12) & 0xfffff)
@@ -192,6 +196,8 @@ enum {
 	NVME_CSTS_SHST_OCCUR	= 1 << 2,
 	NVME_CSTS_SHST_CMPLT	= 2 << 2,
 	NVME_CSTS_SHST_MASK	= 3 << 2,
+	NVME_CMBMSC_CRE		= 1 << 0,
+	NVME_CMBMSC_CMSE	= 1 << 1,
 };
 
 struct nvme_id_power_state {
-- 
2.30.0



From its at irrelevant.dk  Fri Jan 15 01:32:18 2021
From: its at irrelevant.dk (Klaus Jensen)
Date: Fri, 15 Jan 2021 07:32:18 +0100
Subject: [PATCH v2] nvme: allow use of cmb on v1.4 controllers
In-Reply-To: <20210115063046.274495-1-its@irrelevant.dk>
References: <20210115063046.274495-1-its@irrelevant.dk>
Message-ID: <YAE28i5Aq0U40fPB@apples.localdomain>

On Jan 15 07:30, Klaus Jensen wrote:
> From: Klaus Jensen <k.jensen at samsung.com>
> 
> Since NVMe v1.4 the Controller Memory Buffer must be explicitly enabled
> by the host.
> 

Sorry, messed up and missed adding the changes for v2.

v2:
  - Do not explicitly check the NVMe version, rely on the presence of
    the new register instead. (Christoph)
  - Use hi_lo_writeq. (Christoph, Keith)
  - Fix missing offset and use pci_bus_address(). (Keith)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-nvme/attachments/20210115/f773e6f3/attachment-0001.sig>

From hare at suse.de  Fri Jan 15 02:15:07 2021
From: hare at suse.de (Hannes Reinecke)
Date: Fri, 15 Jan 2021 08:15:07 +0100
Subject: [PATCH] nvme-core: update NS Attr Changed AEN handling for ANA
 group
In-Reply-To: <DM5PR0601MB3624BB4004C273271F30052AF1A80@DM5PR0601MB3624.namprd06.prod.outlook.com>
References: <20201209155321.GA31729@redsun51.ssa.fujisawa.hgst.com>
 <b9c9e5f9-a447-2a2e-b687-304dd8f3d2b2@suse.de>
 <20201209161911.GA31836@redsun51.ssa.fujisawa.hgst.com>
 <66bad47c-0cd3-8461-3629-146778f15059@suse.de>
 <20201209173936.GA31971@redsun51.ssa.fujisawa.hgst.com>
 <20201209174718.GA19512@lst.de>
 <DM5PR0601MB3624722C4C00B5A7EDB7E6A0F1CC0@DM5PR0601MB3624.namprd06.prod.outlook.com>
 <20201209213437.GA3682670@dhcp-10-100-145-180.wdc.com>
 <20201210085111.GA15999@lst.de>
 <baa8c2e6-1376-1cad-4c84-1129bd80d4ca@suse.de>
 <20201210133418.GA3645@redsun51.ssa.fujisawa.hgst.com>
 <eb84db43-5e63-19b4-cdb9-53f52d1c45e8@grimberg.me>
 <DM5PR0601MB3624BB4004C273271F30052AF1A80@DM5PR0601MB3624.namprd06.prod.outlook.com>
Message-ID: <3f96f147-cc19-f799-7832-0391459828ea@suse.de>

On 1/14/21 11:59 PM, Knight, Frederick wrote:
> Attached is the proposed clarification.  This has had ZERO review time in the NVMe committee.  So just FYI at this point.
> 
> Feel free to share thoughts.
> 
Thumbs up from my side.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare at suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 N?rnberg
HRB 36809 (AG N?rnberg), Gesch?ftsf?hrer: Felix Imend?rffer


From lkp at intel.com  Fri Jan 15 03:01:33 2021
From: lkp at intel.com (kernel test robot)
Date: Fri, 15 Jan 2021 16:01:33 +0800
Subject: [linux-nvme:nvme-5.11] BUILD SUCCESS
 94900716af1770eb3067ab8210d90c0af67e0694
Message-ID: <60014bdd.3hkK6FWLm2EaFucf%lkp@intel.com>

tree/branch: git://git.infradead.org/nvme.git nvme-5.11
branch HEAD: 94900716af1770eb3067ab8210d90c0af67e0694  nvme: don't intialize hwmon for discovery controllers

elapsed time: 728m

configs tested: 103
configs skipped: 2

The following configs have been built successfully.
More configs may be tested in the coming days.

gcc tested configs:
arm                                 defconfig
arm64                            allyesconfig
arm64                               defconfig
arm                              allyesconfig
arm                              allmodconfig
arm                       aspeed_g4_defconfig
sh                          r7785rp_defconfig
mips                         tb0226_defconfig
powerpc                  iss476-smp_defconfig
mips                           gcw0_defconfig
openrisc                         alldefconfig
arm                        multi_v5_defconfig
sh                            migor_defconfig
powerpc                      ppc44x_defconfig
arc                        nsimosci_defconfig
ia64                             allmodconfig
mips                      bmips_stb_defconfig
powerpc                      ppc6xx_defconfig
arm                             ezx_defconfig
powerpc                     mpc5200_defconfig
mips                        workpad_defconfig
mips                  decstation_64_defconfig
arm                          pxa168_defconfig
powerpc                      cm5200_defconfig
arc                    vdk_hs38_smp_defconfig
powerpc                     sbc8548_defconfig
mips                           ci20_defconfig
sh                          rsk7203_defconfig
sh                               alldefconfig
parisc                generic-32bit_defconfig
sh                     sh7710voipgw_defconfig
mips                        nlm_xlp_defconfig
mips                   sb1250_swarm_defconfig
ia64                                defconfig
ia64                             allyesconfig
m68k                             allmodconfig
m68k                                defconfig
m68k                             allyesconfig
nios2                               defconfig
arc                              allyesconfig
nds32                             allnoconfig
c6x                              allyesconfig
nds32                               defconfig
nios2                            allyesconfig
csky                                defconfig
alpha                               defconfig
alpha                            allyesconfig
xtensa                           allyesconfig
h8300                            allyesconfig
arc                                 defconfig
sh                               allmodconfig
parisc                              defconfig
s390                             allyesconfig
parisc                           allyesconfig
s390                                defconfig
i386                             allyesconfig
sparc                            allyesconfig
sparc                               defconfig
i386                               tinyconfig
i386                                defconfig
mips                             allyesconfig
mips                             allmodconfig
powerpc                          allyesconfig
powerpc                          allmodconfig
powerpc                           allnoconfig
i386                 randconfig-a002-20210114
i386                 randconfig-a005-20210114
i386                 randconfig-a006-20210114
i386                 randconfig-a001-20210114
i386                 randconfig-a003-20210114
i386                 randconfig-a004-20210114
x86_64               randconfig-a015-20210114
x86_64               randconfig-a012-20210114
x86_64               randconfig-a013-20210114
x86_64               randconfig-a016-20210114
x86_64               randconfig-a014-20210114
x86_64               randconfig-a011-20210114
i386                 randconfig-a012-20210114
i386                 randconfig-a011-20210114
i386                 randconfig-a016-20210114
i386                 randconfig-a015-20210114
i386                 randconfig-a013-20210114
i386                 randconfig-a014-20210114
riscv                    nommu_k210_defconfig
riscv                            allyesconfig
riscv                    nommu_virt_defconfig
riscv                             allnoconfig
riscv                               defconfig
riscv                          rv32_defconfig
riscv                            allmodconfig
x86_64                                   rhel
x86_64                           allyesconfig
x86_64                    rhel-7.6-kselftests
x86_64                              defconfig
x86_64                               rhel-8.3
x86_64                      rhel-8.3-kbuiltin
x86_64                                  kexec

clang tested configs:
x86_64               randconfig-a004-20210114
x86_64               randconfig-a006-20210114
x86_64               randconfig-a001-20210114
x86_64               randconfig-a003-20210114
x86_64               randconfig-a005-20210114
x86_64               randconfig-a002-20210114

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all at lists.01.org


From kbusch at kernel.org  Fri Jan 15 12:04:12 2021
From: kbusch at kernel.org (Keith Busch)
Date: Fri, 15 Jan 2021 09:04:12 -0800
Subject: [PATCH V3 3/3] nvme: retry commands based on ACRE flag
In-Reply-To: <20210114133110.20779-4-minwoo.im.dev@gmail.com>
References: <20210114133110.20779-1-minwoo.im.dev@gmail.com>
 <20210114133110.20779-4-minwoo.im.dev@gmail.com>
Message-ID: <20210115170412.GA1515933@dhcp-10-100-145-180.wdc.com>

On Thu, Jan 14, 2021 at 10:31:10PM +0900, Minwoo Im wrote:
> @@ -317,6 +316,13 @@ static inline enum nvme_disposition nvme_decide_disposition(struct request *req)
>  			return COMPLETE;
>  	}
>  
> +	if (nvme_req(req)->ctrl->acre &&
> +	    !nvme_is_path_error(nvme_req(req)->status) &&
> +	    !blk_queue_dying(req->q))
> +		return RETRY;

Is there really any reason to tie this to acre?

> +	else if (blk_noretry_request(req))
> +		return COMPLETE;

I am not sure we should ignore the FAILFAST for non-path errors. If we
need retryable admin commands, we should let the driver provide a way
for callers to dispatch requests without that flag.


From minwoo.im.dev at gmail.com  Fri Jan 15 13:26:02 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Sat, 16 Jan 2021 03:26:02 +0900
Subject: [PATCH V3 3/3] nvme: retry commands based on ACRE flag
In-Reply-To: <20210115170412.GA1515933@dhcp-10-100-145-180.wdc.com>
References: <20210114133110.20779-1-minwoo.im.dev@gmail.com>
 <20210114133110.20779-4-minwoo.im.dev@gmail.com>
 <20210115170412.GA1515933@dhcp-10-100-145-180.wdc.com>
Message-ID: <20210115182602.GA2822@localhost.localdomain>

On 21-01-15 09:04:12, Keith Busch wrote:
> On Thu, Jan 14, 2021 at 10:31:10PM +0900, Minwoo Im wrote:
> > @@ -317,6 +316,13 @@ static inline enum nvme_disposition nvme_decide_disposition(struct request *req)
> >  			return COMPLETE;
> >  	}
> >  
> > +	if (nvme_req(req)->ctrl->acre &&
> > +	    !nvme_is_path_error(nvme_req(req)->status) &&
> > +	    !blk_queue_dying(req->q))
> > +		return RETRY;
> 
> Is there really any reason to tie this to acre?
> 
> > +	else if (blk_noretry_request(req))
> > +		return COMPLETE;
> 
> I am not sure we should ignore the FAILFAST for non-path errors. If we
> need retryable admin commands, we should let the driver provide a way
> for callers to dispatch requests without that flag.

Understood.  I thought the opposite way about FAILFAST in case with
acre, if device is enabled with acre, all commands would be retried
regardless to FAILFAST...  Thanks for pointing that out!

How do you think which one is right choice to go with if a user-space
application(e.g., nvme-cli) wants a command to be retired in case of
ACRE && Error && !DNR:

  - User-space application should figure out !DNR and retry the command.
    (Maybe we are not able to easily figure out exact status code from
    the user-space application by the return value).

  - Driver should retry the command right before putting result up to
    the user-space even it's a FAILFAST request.

Thanks,


From minwoo.im.dev at gmail.com  Fri Jan 15 13:40:46 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Sat, 16 Jan 2021 03:40:46 +0900
Subject: [PATCH 1/3] nvme: support command retry delay for admin command
In-Reply-To: <20210114072254.GA517@lst.de>
References: <20210108144659.7126-1-minwoo.im.dev@gmail.com>
 <20210108144659.7126-2-minwoo.im.dev@gmail.com>
 <20210112080653.GB24949@lst.de> <20210114072254.GA517@lst.de>
Message-ID: <20210115184046.GC2822@localhost.localdomain>

On 21-01-14 08:22:54, Christoph Hellwig wrote:
> On Tue, Jan 12, 2021 at 09:06:53AM +0100, Christoph Hellwig wrote:
> > Except for the little wording issue this looks good to me.  I'll pick it
> > up for nvme-5.11 and will fix up the commit log.
> 
> Given that we never retry admin command right now I've moved this off 
> nvme-5.11 into the pending queue.

Thanks for sharing!


From sagi at grimberg.me  Fri Jan 15 20:18:37 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Fri, 15 Jan 2021 17:18:37 -0800
Subject: [PATCH v2 4/6] nvme-rdma: avoid IO error and repeated request
 completion
In-Reply-To: <695b6839-5333-c342-2189-d7aaeba797a7@huawei.com>
References: <20210107033149.15701-1-lengchao@huawei.com>
 <20210107033149.15701-5-lengchao@huawei.com>
 <07e41b4f-914a-11e8-5638-e2d6408feb3f@grimberg.me>
 <7b12be41-0fcd-5a22-0e01-8cd4ac9cde5b@huawei.com>
 <a3404c7d-ccc8-0d55-d4a8-fc15107c90e6@grimberg.me>
 <695b6839-5333-c342-2189-d7aaeba797a7@huawei.com>
Message-ID: <4ff22d33-12fa-1f70-3606-54821f314c45@grimberg.me>


>>>>> When a request is queued failed, blk_status_t is directly returned
>>>>> to the blk-mq. If blk_status_t is not BLK_STS_RESOURCE,
>>>>> BLK_STS_DEV_RESOURCE, BLK_STS_ZONE_RESOURCE, blk-mq call
>>>>> blk_mq_end_request to complete the request with BLK_STS_IOERR.
>>>>> In two scenarios, the request should be retried and may succeed.
>>>>> First, if work with nvme multipath, the request may be retried
>>>>> successfully in another path, because the error is probably related to
>>>>> the path. Second, if work without multipath software, the request may
>>>>> be retried successfully after error recovery.
>>>>> If the request is complete with BLK_STS_IOERR in 
>>>>> blk_mq_dispatch_rq_list.
>>>>> The state of request may be changed to MQ_RQ_IN_FLIGHT. If free the
>>>>> request asynchronously such as in nvme_submit_user_cmd, in extreme
>>>>> scenario the request will be repeated freed in tear down.
>>>>> If a non-resource error occurs in queue_rq, should directly call
>>>>> nvme_complete_rq to complete request and set the state of request to
>>>>> MQ_RQ_COMPLETE. nvme_complete_rq will decide to retry, fail over or 
>>>>> end
>>>>> the request.
>>>>>
>>>>> Signed-off-by: Chao Leng <lengchao at huawei.com>
>>>>> ---
>>>>> ? drivers/nvme/host/rdma.c | 2 +-
>>>>> ? 1 file changed, 1 insertion(+), 1 deletion(-)
>>>>>
>>>>> diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
>>>>> index df9f6f4549f1..4a89bf44ecdc 100644
>>>>> --- a/drivers/nvme/host/rdma.c
>>>>> +++ b/drivers/nvme/host/rdma.c
>>>>> @@ -2093,7 +2093,7 @@ static blk_status_t nvme_rdma_queue_rq(struct 
>>>>> blk_mq_hw_ctx *hctx,
>>>>> ? unmap_qe:
>>>>> ????? ib_dma_unmap_single(dev, req->sqe.dma, sizeof(struct 
>>>>> nvme_command),
>>>>> ????????????????? DMA_TO_DEVICE);
>>>>> -??? return ret;
>>>>> +??? return nvme_try_complete_failed_req(rq, ret);
>>>>
>>>> I don't understand this. There are errors that may not be related to
>>>> anything that is pathing related (sw bug, memory leak, mapping error,
>>>> etc, etc) why should we return this one-shot error?
>>> Although fail over retry is not required, if we return the error to
>>> blk-mq, a low probability crash may happen. because blk-mq do not set
>>> the state of request to MQ_RQ_COMPLETE before complete the request,
>>> the request may be freed asynchronously such as in nvme_submit_user_cmd.
>>> If race with error recovery, request double completion may happens.
>>
>> Then fix that, don't work around it.
> I'm not trying to work around it. The purpose of this is to solve
> the problem of nvme native multipathing at the same time.

Please explain how this is an nvme-multipath issue?

>>
>>>
>>> So we can not return the error to blk-mq if the blk_status_t is not
>>> BLK_STS_RESOURCE, BLK_STS_DEV_RESOURCE, BLK_STS_ZONE_RESOURCE.
>>
>> This is not something we should be handling in nvme. block drivers
>> should be able to fail queue_rq, and this all should live in the
>> block layer.
> Of course, it is also an idea to repair the block drivers directly.
> However, block layer is unaware of nvme native multipathing,

Nor it should be

> will cause the request return error which should be avoided.

Not sure I understand..
requests should failover for path related errors,
what queue_rq errors are expected to be failed over from your
perspective?

> The scenario: use two HBAs for nvme native multipath, and then one HBA
> fault,

What is the specific error the driver sees?

> the blk_status_t of queue_rq is BLK_STS_IOERR, blk-mq will call
> blk_mq_end_request to complete the request which bypass name native
> multipath. We expect the request fail over to normal HBA, but the request
> is directly completed with BLK_STS_IOERR.
> The two scenarios can be fixed by directly completing the request in 
> queue_rq.
Well, certainly this one-shot always return 0 and complete the command
with HOST_PATH error is not a good approach IMO


From sagi at grimberg.me  Fri Jan 15 20:19:23 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Fri, 15 Jan 2021 17:19:23 -0800
Subject: [PATCH] nvme-tcp: fix a segmentation fault during io parsing error
In-Reply-To: <DM6PR19MB4011A4116FAB37BEC28BBC91EFA80@DM6PR19MB4011.namprd19.prod.outlook.com>
References: <20210113115152.69692-1-elad.grupi@dell.com>
 <ad9f038b-9920-21da-755c-85f4e2228a22@grimberg.me>
 <DM6PR19MB401194016A086DDF8A82C554EFA80@DM6PR19MB4011.namprd19.prod.outlook.com>
 <f5b8dbc2-7960-894e-47ea-b18665536e70@grimberg.me>
 <DM6PR19MB4011A4116FAB37BEC28BBC91EFA80@DM6PR19MB4011.namprd19.prod.outlook.com>
Message-ID: <6459e22f-f2f2-9183-0862-654bcc5e90eb@grimberg.me>


>> This was a silly typo, did you check if it addressed your issue when you applied the needed change?
> 
> Yes. We applied the needed change before testing your patch, but still had kernel panic on recv flow when we had unread inline data on the socket.


Can you share the stack trace?


From dsahern at gmail.com  Fri Jan 15 23:57:34 2021
From: dsahern at gmail.com (David Ahern)
Date: Fri, 15 Jan 2021 21:57:34 -0700
Subject: [PATCH v2 net-next 19/21] net/mlx5e: NVMEoTCP, data-path for DDP
 offload
In-Reply-To: <20210114151033.13020-20-borisp@mellanox.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
 <20210114151033.13020-20-borisp@mellanox.com>
Message-ID: <10c28b01-49e5-c512-8670-bf8332b24b1b@gmail.com>

I have not had time to review this version of the patches, but this
patch seems very similar to 13 of 15 from v1 and you did not respond to
my question on it ...

On 1/14/21 8:10 AM, Boris Pismenny wrote:
> diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp_rxtx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp_rxtx.c
> new file mode 100644
> index 000000000000..f446b5d56d64
> --- /dev/null
> +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp_rxtx.c
> @@ -0,0 +1,243 @@
> +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
> +/* Copyright (c) 2021 Mellanox Technologies. */
> +
> +#include "en_accel/nvmeotcp_rxtx.h"
> +#include "en_accel/nvmeotcp.h"
> +#include <linux/mlx5/mlx5_ifc.h>
> +
> +#define	MLX5E_TC_FLOW_ID_MASK  0x00ffffff
> +static void nvmeotcp_update_resync(struct mlx5e_nvmeotcp_queue *queue,
> +				   struct mlx5e_cqe128 *cqe128)
> +{
> +	const struct tcp_ddp_ulp_ops *ulp_ops;
> +	u32 seq;
> +
> +	seq = be32_to_cpu(cqe128->resync_tcp_sn);
> +	ulp_ops = inet_csk(queue->sk)->icsk_ulp_ddp_ops;
> +	if (ulp_ops && ulp_ops->resync_request)
> +		ulp_ops->resync_request(queue->sk, seq, TCP_DDP_RESYNC_REQ);
> +}
> +
> +static void mlx5e_nvmeotcp_advance_sgl_iter(struct mlx5e_nvmeotcp_queue *queue)
> +{
> +	struct nvmeotcp_queue_entry *nqe = &queue->ccid_table[queue->ccid];
> +
> +	queue->ccoff += nqe->sgl[queue->ccsglidx].length;
> +	queue->ccoff_inner = 0;
> +	queue->ccsglidx++;
> +}
> +
> +static inline void
> +mlx5e_nvmeotcp_add_skb_frag(struct net_device *netdev, struct sk_buff *skb,
> +			    struct mlx5e_nvmeotcp_queue *queue,
> +			    struct nvmeotcp_queue_entry *nqe, u32 fragsz)
> +{
> +	dma_sync_single_for_cpu(&netdev->dev,
> +				nqe->sgl[queue->ccsglidx].offset + queue->ccoff_inner,
> +				fragsz, DMA_FROM_DEVICE);
> +	page_ref_inc(compound_head(sg_page(&nqe->sgl[queue->ccsglidx])));
> +	// XXX: consider reducing the truesize, as no new memory is consumed
> +	skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
> +			sg_page(&nqe->sgl[queue->ccsglidx]),
> +			nqe->sgl[queue->ccsglidx].offset + queue->ccoff_inner,
> +			fragsz,
> +			fragsz);
> +}
> +
> +static struct sk_buff*
> +mlx5_nvmeotcp_add_tail_nonlinear(struct mlx5e_nvmeotcp_queue *queue,
> +				 struct sk_buff *skb, skb_frag_t *org_frags,
> +				 int org_nr_frags, int frag_index)
> +{
> +	struct mlx5e_priv *priv = queue->priv;
> +
> +	while (org_nr_frags != frag_index) {
> +		if (skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS) {
> +			dev_kfree_skb_any(skb);
> +			return NULL;
> +		}
> +		skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
> +				skb_frag_page(&org_frags[frag_index]),
> +				skb_frag_off(&org_frags[frag_index]),
> +				skb_frag_size(&org_frags[frag_index]),
> +				skb_frag_size(&org_frags[frag_index]));
> +		page_ref_inc(skb_frag_page(&org_frags[frag_index]));
> +		frag_index++;
> +	}
> +	return skb;
> +}
> +
> +static struct sk_buff*
> +mlx5_nvmeotcp_add_tail(struct mlx5e_nvmeotcp_queue *queue, struct sk_buff *skb,
> +		       int offset, int len)
> +{
> +	struct mlx5e_priv *priv = queue->priv;
> +
> +	if (skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS) {
> +		dev_kfree_skb_any(skb);
> +		return NULL;
> +	}
> +	skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
> +			virt_to_page(skb->data),
> +			offset,
> +			len,
> +			len);
> +	page_ref_inc(virt_to_page(skb->data));
> +	return skb;
> +}
> +
> +static void mlx5_nvmeotcp_trim_nonlinear(struct sk_buff *skb,
> +					 skb_frag_t *org_frags,
> +					 int *frag_index,
> +					 int remaining)
> +{
> +	unsigned int frag_size;
> +	int nr_frags;
> +
> +	/* skip @remaining bytes in frags */
> +	*frag_index = 0;
> +	while (remaining) {
> +		frag_size = skb_frag_size(&skb_shinfo(skb)->frags[*frag_index]);
> +		if (frag_size > remaining) {
> +			skb_frag_off_add(&skb_shinfo(skb)->frags[*frag_index],
> +					 remaining);
> +			skb_frag_size_sub(&skb_shinfo(skb)->frags[*frag_index],
> +					  remaining);
> +			remaining = 0;
> +		} else {
> +			remaining -= frag_size;
> +			skb_frag_unref(skb, *frag_index);
> +			*frag_index += 1;
> +		}
> +	}
> +
> +	/* save original frags for the tail and unref */
> +	nr_frags = skb_shinfo(skb)->nr_frags;
> +	memcpy(&org_frags[*frag_index], &skb_shinfo(skb)->frags[*frag_index],
> +	       (nr_frags - *frag_index) * sizeof(skb_frag_t));
> +	while (--nr_frags >= *frag_index)
> +		skb_frag_unref(skb, nr_frags);
> +
> +	/* remove frags from skb */
> +	skb_shinfo(skb)->nr_frags = 0;
> +	skb->len -= skb->data_len;
> +	skb->truesize -= skb->data_len;
> +	skb->data_len = 0;
> +}
> +
> +struct sk_buff*
> +mlx5e_nvmeotcp_handle_rx_skb(struct net_device *netdev, struct sk_buff *skb,
> +			     struct mlx5_cqe64 *cqe, u32 cqe_bcnt,
> +			     bool linear)
> +{
> +	int ccoff, cclen, hlen, ccid, remaining, fragsz, to_copy = 0;
> +	struct mlx5e_priv *priv = netdev_priv(netdev);
> +	skb_frag_t org_frags[MAX_SKB_FRAGS];
> +	struct mlx5e_nvmeotcp_queue *queue;
> +	struct nvmeotcp_queue_entry *nqe;
> +	int org_nr_frags, frag_index;
> +	struct mlx5e_cqe128 *cqe128;
> +	u32 queue_id;
> +
> +	queue_id = (be32_to_cpu(cqe->sop_drop_qpn) & MLX5E_TC_FLOW_ID_MASK);
> +	queue = mlx5e_nvmeotcp_get_queue(priv->nvmeotcp, queue_id);
> +	if (unlikely(!queue)) {
> +		dev_kfree_skb_any(skb);
> +		return NULL;
> +	}
> +
> +	cqe128 = container_of(cqe, struct mlx5e_cqe128, cqe64);
> +	if (cqe_is_nvmeotcp_resync(cqe)) {
> +		nvmeotcp_update_resync(queue, cqe128);
> +		mlx5e_nvmeotcp_put_queue(queue);
> +		return skb;
> +	}
> +
> +#ifdef CONFIG_TCP_DDP_CRC
> +	/* If a resync occurred in the previous cqe,
> +	 * the current cqe.crcvalid bit may not be valid,
> +	 * so we will treat it as 0
> +	 */
> +	skb->ddp_crc = queue->after_resync_cqe ? 0 :
> +		cqe_is_nvmeotcp_crcvalid(cqe);
> +	queue->after_resync_cqe = 0;
> +#endif
> +	if (!cqe_is_nvmeotcp_zc(cqe)) {
> +		mlx5e_nvmeotcp_put_queue(queue);
> +		return skb;
> +	}
> +
> +	/* cc ddp from cqe */
> +	ccid = be16_to_cpu(cqe128->ccid);
> +	ccoff = be32_to_cpu(cqe128->ccoff);
> +	cclen = be16_to_cpu(cqe128->cclen);
> +	hlen  = be16_to_cpu(cqe128->hlen);
> +
> +	/* carve a hole in the skb for DDP data */
> +	if (linear) {
> +		skb_trim(skb, hlen);
> +	} else {
> +		org_nr_frags = skb_shinfo(skb)->nr_frags;
> +		mlx5_nvmeotcp_trim_nonlinear(skb, org_frags, &frag_index,
> +					     cclen);
> +	}
> +
> +	nqe = &queue->ccid_table[ccid];
> +
> +	/* packet starts new ccid? */
> +	if (queue->ccid != ccid || queue->ccid_gen != nqe->ccid_gen) {
> +		queue->ccid = ccid;
> +		queue->ccoff = 0;
> +		queue->ccoff_inner = 0;
> +		queue->ccsglidx = 0;
> +		queue->ccid_gen = nqe->ccid_gen;
> +	}
> +
> +	/* skip inside cc until the ccoff in the cqe */
> +	while (queue->ccoff + queue->ccoff_inner < ccoff) {
> +		remaining = nqe->sgl[queue->ccsglidx].length - queue->ccoff_inner;
> +		fragsz = min_t(off_t, remaining,
> +			       ccoff - (queue->ccoff + queue->ccoff_inner));
> +
> +		if (fragsz == remaining)
> +			mlx5e_nvmeotcp_advance_sgl_iter(queue);
> +		else
> +			queue->ccoff_inner += fragsz;
> +	}
> +
> +	/* adjust the skb according to the cqe cc */
> +	while (to_copy < cclen) {
> +		if (skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS) {
> +			dev_kfree_skb_any(skb);
> +			mlx5e_nvmeotcp_put_queue(queue);
> +			return NULL;
> +		}
> +
> +		remaining = nqe->sgl[queue->ccsglidx].length - queue->ccoff_inner;
> +		fragsz = min_t(int, remaining, cclen - to_copy);
> +
> +		mlx5e_nvmeotcp_add_skb_frag(netdev, skb, queue, nqe, fragsz);
> +		to_copy += fragsz;
> +		if (fragsz == remaining)
> +			mlx5e_nvmeotcp_advance_sgl_iter(queue);
> +		else
> +			queue->ccoff_inner += fragsz;
> +	}
> +
> +	if (cqe_bcnt > hlen + cclen) {
> +		remaining = cqe_bcnt - hlen - cclen;
> +		if (linear)
> +			skb = mlx5_nvmeotcp_add_tail(queue, skb,
> +						     offset_in_page(skb->data) +
> +								hlen + cclen,
> +						     remaining);
> +		else
> +			skb = mlx5_nvmeotcp_add_tail_nonlinear(queue, skb,
> +							       org_frags,
> +							       org_nr_frags,
> +							       frag_index);
> +	}
> +
> +	mlx5e_nvmeotcp_put_queue(queue);
> +	return skb;
> +}



... I'll copy and paste my question here:

"mlx5e_skb_from_cqe_mpwrq_linear and mlx5e_skb_from_cqe_mpwrq_nolinear
create an skb and then this function comes behind it, strips any frags
originally added to the skb, adds the frags for the sgls, and then
re-adds the original frags.

Why is this needed? Why can't the skb be created with all of the frags
in proper order?

It seems like this dance is not needed if you had generic header/payload
splits with the payload written to less retrictive SGLs."

This patch seems to be something very similar, and it is really
complicated way to create each skb for DDP. The patch description does
little to explain why it is needed.


From borispismenny at gmail.com  Sun Jan 17 03:42:20 2021
From: borispismenny at gmail.com (Boris Pismenny)
Date: Sun, 17 Jan 2021 10:42:20 +0200
Subject: [PATCH v2 net-next 19/21] net/mlx5e: NVMEoTCP, data-path for DDP
 offload
In-Reply-To: <10c28b01-49e5-c512-8670-bf8332b24b1b@gmail.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
 <20210114151033.13020-20-borisp@mellanox.com>
 <10c28b01-49e5-c512-8670-bf8332b24b1b@gmail.com>
Message-ID: <15248743-82bf-4283-d8c6-99f2210e42ae@gmail.com>

On 16/01/2021 6:57, David Ahern wrote:
> I have not had time to review this version of the patches, but this
> patch seems very similar to 13 of 15 from v1 and you did not respond to
> my question on it ...
> 
> On 1/14/21 8:10 AM, Boris Pismenny wrote:
>> diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp_rxtx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp_rxtx.c
>> new file mode 100644
>> index 000000000000..f446b5d56d64
>> --- /dev/null
>> +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/nvmeotcp_rxtx.c
>> @@ -0,0 +1,243 @@
>> +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
>> +/* Copyright (c) 2021 Mellanox Technologies. */
>> +
>> +#include "en_accel/nvmeotcp_rxtx.h"
>> +#include "en_accel/nvmeotcp.h"
>> +#include <linux/mlx5/mlx5_ifc.h>
>> +
>> +#define	MLX5E_TC_FLOW_ID_MASK  0x00ffffff
>> +static void nvmeotcp_update_resync(struct mlx5e_nvmeotcp_queue *queue,
>> +				   struct mlx5e_cqe128 *cqe128)
>> +{
>> +	const struct tcp_ddp_ulp_ops *ulp_ops;
>> +	u32 seq;
>> +
>> +	seq = be32_to_cpu(cqe128->resync_tcp_sn);
>> +	ulp_ops = inet_csk(queue->sk)->icsk_ulp_ddp_ops;
>> +	if (ulp_ops && ulp_ops->resync_request)
>> +		ulp_ops->resync_request(queue->sk, seq, TCP_DDP_RESYNC_REQ);
>> +}
>> +
>> +static void mlx5e_nvmeotcp_advance_sgl_iter(struct mlx5e_nvmeotcp_queue *queue)
>> +{
>> +	struct nvmeotcp_queue_entry *nqe = &queue->ccid_table[queue->ccid];
>> +
>> +	queue->ccoff += nqe->sgl[queue->ccsglidx].length;
>> +	queue->ccoff_inner = 0;
>> +	queue->ccsglidx++;
>> +}
>> +
>> +static inline void
>> +mlx5e_nvmeotcp_add_skb_frag(struct net_device *netdev, struct sk_buff *skb,
>> +			    struct mlx5e_nvmeotcp_queue *queue,
>> +			    struct nvmeotcp_queue_entry *nqe, u32 fragsz)
>> +{
>> +	dma_sync_single_for_cpu(&netdev->dev,
>> +				nqe->sgl[queue->ccsglidx].offset + queue->ccoff_inner,
>> +				fragsz, DMA_FROM_DEVICE);
>> +	page_ref_inc(compound_head(sg_page(&nqe->sgl[queue->ccsglidx])));
>> +	// XXX: consider reducing the truesize, as no new memory is consumed
>> +	skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
>> +			sg_page(&nqe->sgl[queue->ccsglidx]),
>> +			nqe->sgl[queue->ccsglidx].offset + queue->ccoff_inner,
>> +			fragsz,
>> +			fragsz);
>> +}
>> +
>> +static struct sk_buff*
>> +mlx5_nvmeotcp_add_tail_nonlinear(struct mlx5e_nvmeotcp_queue *queue,
>> +				 struct sk_buff *skb, skb_frag_t *org_frags,
>> +				 int org_nr_frags, int frag_index)
>> +{
>> +	struct mlx5e_priv *priv = queue->priv;
>> +
>> +	while (org_nr_frags != frag_index) {
>> +		if (skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS) {
>> +			dev_kfree_skb_any(skb);
>> +			return NULL;
>> +		}
>> +		skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
>> +				skb_frag_page(&org_frags[frag_index]),
>> +				skb_frag_off(&org_frags[frag_index]),
>> +				skb_frag_size(&org_frags[frag_index]),
>> +				skb_frag_size(&org_frags[frag_index]));
>> +		page_ref_inc(skb_frag_page(&org_frags[frag_index]));
>> +		frag_index++;
>> +	}
>> +	return skb;
>> +}
>> +
>> +static struct sk_buff*
>> +mlx5_nvmeotcp_add_tail(struct mlx5e_nvmeotcp_queue *queue, struct sk_buff *skb,
>> +		       int offset, int len)
>> +{
>> +	struct mlx5e_priv *priv = queue->priv;
>> +
>> +	if (skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS) {
>> +		dev_kfree_skb_any(skb);
>> +		return NULL;
>> +	}
>> +	skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
>> +			virt_to_page(skb->data),
>> +			offset,
>> +			len,
>> +			len);
>> +	page_ref_inc(virt_to_page(skb->data));
>> +	return skb;
>> +}
>> +
>> +static void mlx5_nvmeotcp_trim_nonlinear(struct sk_buff *skb,
>> +					 skb_frag_t *org_frags,
>> +					 int *frag_index,
>> +					 int remaining)
>> +{
>> +	unsigned int frag_size;
>> +	int nr_frags;
>> +
>> +	/* skip @remaining bytes in frags */
>> +	*frag_index = 0;
>> +	while (remaining) {
>> +		frag_size = skb_frag_size(&skb_shinfo(skb)->frags[*frag_index]);
>> +		if (frag_size > remaining) {
>> +			skb_frag_off_add(&skb_shinfo(skb)->frags[*frag_index],
>> +					 remaining);
>> +			skb_frag_size_sub(&skb_shinfo(skb)->frags[*frag_index],
>> +					  remaining);
>> +			remaining = 0;
>> +		} else {
>> +			remaining -= frag_size;
>> +			skb_frag_unref(skb, *frag_index);
>> +			*frag_index += 1;
>> +		}
>> +	}
>> +
>> +	/* save original frags for the tail and unref */
>> +	nr_frags = skb_shinfo(skb)->nr_frags;
>> +	memcpy(&org_frags[*frag_index], &skb_shinfo(skb)->frags[*frag_index],
>> +	       (nr_frags - *frag_index) * sizeof(skb_frag_t));
>> +	while (--nr_frags >= *frag_index)
>> +		skb_frag_unref(skb, nr_frags);
>> +
>> +	/* remove frags from skb */
>> +	skb_shinfo(skb)->nr_frags = 0;
>> +	skb->len -= skb->data_len;
>> +	skb->truesize -= skb->data_len;
>> +	skb->data_len = 0;
>> +}
>> +
>> +struct sk_buff*
>> +mlx5e_nvmeotcp_handle_rx_skb(struct net_device *netdev, struct sk_buff *skb,
>> +			     struct mlx5_cqe64 *cqe, u32 cqe_bcnt,
>> +			     bool linear)
>> +{
>> +	int ccoff, cclen, hlen, ccid, remaining, fragsz, to_copy = 0;
>> +	struct mlx5e_priv *priv = netdev_priv(netdev);
>> +	skb_frag_t org_frags[MAX_SKB_FRAGS];
>> +	struct mlx5e_nvmeotcp_queue *queue;
>> +	struct nvmeotcp_queue_entry *nqe;
>> +	int org_nr_frags, frag_index;
>> +	struct mlx5e_cqe128 *cqe128;
>> +	u32 queue_id;
>> +
>> +	queue_id = (be32_to_cpu(cqe->sop_drop_qpn) & MLX5E_TC_FLOW_ID_MASK);
>> +	queue = mlx5e_nvmeotcp_get_queue(priv->nvmeotcp, queue_id);
>> +	if (unlikely(!queue)) {
>> +		dev_kfree_skb_any(skb);
>> +		return NULL;
>> +	}
>> +
>> +	cqe128 = container_of(cqe, struct mlx5e_cqe128, cqe64);
>> +	if (cqe_is_nvmeotcp_resync(cqe)) {
>> +		nvmeotcp_update_resync(queue, cqe128);
>> +		mlx5e_nvmeotcp_put_queue(queue);
>> +		return skb;
>> +	}
>> +
>> +#ifdef CONFIG_TCP_DDP_CRC
>> +	/* If a resync occurred in the previous cqe,
>> +	 * the current cqe.crcvalid bit may not be valid,
>> +	 * so we will treat it as 0
>> +	 */
>> +	skb->ddp_crc = queue->after_resync_cqe ? 0 :
>> +		cqe_is_nvmeotcp_crcvalid(cqe);
>> +	queue->after_resync_cqe = 0;
>> +#endif
>> +	if (!cqe_is_nvmeotcp_zc(cqe)) {
>> +		mlx5e_nvmeotcp_put_queue(queue);
>> +		return skb;
>> +	}
>> +
>> +	/* cc ddp from cqe */
>> +	ccid = be16_to_cpu(cqe128->ccid);
>> +	ccoff = be32_to_cpu(cqe128->ccoff);
>> +	cclen = be16_to_cpu(cqe128->cclen);
>> +	hlen  = be16_to_cpu(cqe128->hlen);
>> +
>> +	/* carve a hole in the skb for DDP data */
>> +	if (linear) {
>> +		skb_trim(skb, hlen);
>> +	} else {
>> +		org_nr_frags = skb_shinfo(skb)->nr_frags;
>> +		mlx5_nvmeotcp_trim_nonlinear(skb, org_frags, &frag_index,
>> +					     cclen);
>> +	}
>> +
>> +	nqe = &queue->ccid_table[ccid];
>> +
>> +	/* packet starts new ccid? */
>> +	if (queue->ccid != ccid || queue->ccid_gen != nqe->ccid_gen) {
>> +		queue->ccid = ccid;
>> +		queue->ccoff = 0;
>> +		queue->ccoff_inner = 0;
>> +		queue->ccsglidx = 0;
>> +		queue->ccid_gen = nqe->ccid_gen;
>> +	}
>> +
>> +	/* skip inside cc until the ccoff in the cqe */
>> +	while (queue->ccoff + queue->ccoff_inner < ccoff) {
>> +		remaining = nqe->sgl[queue->ccsglidx].length - queue->ccoff_inner;
>> +		fragsz = min_t(off_t, remaining,
>> +			       ccoff - (queue->ccoff + queue->ccoff_inner));
>> +
>> +		if (fragsz == remaining)
>> +			mlx5e_nvmeotcp_advance_sgl_iter(queue);
>> +		else
>> +			queue->ccoff_inner += fragsz;
>> +	}
>> +
>> +	/* adjust the skb according to the cqe cc */
>> +	while (to_copy < cclen) {
>> +		if (skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS) {
>> +			dev_kfree_skb_any(skb);
>> +			mlx5e_nvmeotcp_put_queue(queue);
>> +			return NULL;
>> +		}
>> +
>> +		remaining = nqe->sgl[queue->ccsglidx].length - queue->ccoff_inner;
>> +		fragsz = min_t(int, remaining, cclen - to_copy);
>> +
>> +		mlx5e_nvmeotcp_add_skb_frag(netdev, skb, queue, nqe, fragsz);
>> +		to_copy += fragsz;
>> +		if (fragsz == remaining)
>> +			mlx5e_nvmeotcp_advance_sgl_iter(queue);
>> +		else
>> +			queue->ccoff_inner += fragsz;
>> +	}
>> +
>> +	if (cqe_bcnt > hlen + cclen) {
>> +		remaining = cqe_bcnt - hlen - cclen;
>> +		if (linear)
>> +			skb = mlx5_nvmeotcp_add_tail(queue, skb,
>> +						     offset_in_page(skb->data) +
>> +								hlen + cclen,
>> +						     remaining);
>> +		else
>> +			skb = mlx5_nvmeotcp_add_tail_nonlinear(queue, skb,
>> +							       org_frags,
>> +							       org_nr_frags,
>> +							       frag_index);
>> +	}
>> +
>> +	mlx5e_nvmeotcp_put_queue(queue);
>> +	return skb;
>> +}
> 
> 
> 
> ... I'll copy and paste my question here:
> 
> "mlx5e_skb_from_cqe_mpwrq_linear and mlx5e_skb_from_cqe_mpwrq_nolinear
> create an skb and then this function comes behind it, strips any frags
> originally added to the skb, adds the frags for the sgls, and then
> re-adds the original frags.
> 
> Why is this needed? Why can't the skb be created with all of the frags
> in proper order?
> 
> It seems like this dance is not needed if you had generic header/payload
> splits with the payload written to less retrictive SGLs."
> 
> This patch seems to be something very similar, and it is really
> complicated way to create each skb for DDP. The patch description does
> little to explain why it is needed.
> 

This is the same patch as before.

I'll start by explaining why this is needed. Then, clarify why generic
header-data split is not enough.

This is needed for a few reasons that are explained in detail
in the tcp-ddp offload documentation. See patch 21 overview
and rx-data-path sections. Our reasons are as follows:
1) Each SKB may contain multiple PDUs. DDP offload doesn't operate on
PDU headers, so these are written in the receive ring. Therefore, we
need to rebuild the SKB to account for it. Additionally, due to HW
limitations, we will only offload the first PDU in the SKB.
2) The newly constructed SKB represents the original data as it is on
the wire, such that the network stack is oblivious to the offload.
3) We decided not to modify all of the mlx5e_skb_from_cqe* functions
because it would make the offload harder to distinguish, and it would
add overhead to the existing data-path fucntions. Therefore, we opted
for this modular approach.

If we only had generic header-data split, then we just couldn't
provide this offload. It is not enough to place payload into some
buffer without TCP headers because RPC protocols and advanced storage
protocols, such as nvme-tcp, reorder their responses and require data
to be placed into application/pagecache buffers, which are anything
but anonymous. In other words, header-data split alone writes data
to the wrong buffers (reordering), or to anonymous buffers that
can't be page-flipped to replace application/pagecache buffers.



From Elad.Grupi at dell.com  Sun Jan 17 04:46:55 2021
From: Elad.Grupi at dell.com (Grupi, Elad)
Date: Sun, 17 Jan 2021 09:46:55 +0000
Subject: [PATCH] nvme-tcp: fix a segmentation fault during io parsing error
In-Reply-To: <6459e22f-f2f2-9183-0862-654bcc5e90eb@grimberg.me>
References: <20210113115152.69692-1-elad.grupi@dell.com>
 <ad9f038b-9920-21da-755c-85f4e2228a22@grimberg.me>
 <DM6PR19MB401194016A086DDF8A82C554EFA80@DM6PR19MB4011.namprd19.prod.outlook.com>
 <f5b8dbc2-7960-894e-47ea-b18665536e70@grimberg.me>
 <DM6PR19MB4011A4116FAB37BEC28BBC91EFA80@DM6PR19MB4011.namprd19.prod.outlook.com>
 <6459e22f-f2f2-9183-0862-654bcc5e90eb@grimberg.me>
Message-ID: <DM6PR19MB4011D61F1BF2A4F66228E9EEEFA50@DM6PR19MB4011.namprd19.prod.outlook.com>

Yes, it was reproduced with the validity check of resv1 field of connect command.

Jan 17 09:43:36 FNM00183301763-A kernel: nvmet_tcp: failed cmd 000000006fe9c801 id 0 opcode 127, data_len: 1024                                                                                                                                          
Jan 17 09:43:36 FNM00183301763-A kernel: general protection fault: 0000 [#1] SMP NOPTI                                                                                                                                                                   
Jan 17 09:43:36 FNM00183301763-A kernel: CPU: 10 PID: 615 Comm: kworker/10:1H Kdump: loaded Tainted: P           OE     4.19.158-coreos-r9999.188fe4a1ba192d57eaaa3462db70e1d9 #1                                                                        
Jan 17 09:43:36 FNM00183301763-A kernel: Hardware name: EMC 900-532-002/110-551-910C-01, BIOS 20.12 11/12/2020                                                                                                                                           
Jan 17 09:43:36 FNM00183301763-A kernel: Workqueue: nvmet_tcp_wq nvmet_tcp_io_work [nvmet_tcp]                                                                                                                                                           
Jan 17 09:43:36 FNM00183301763-A kernel: RIP: 0010:memcpy_erms+0x6/0x10                                                                                                                                                                                  
Jan 17 09:43:36 FNM00183301763-A kernel: Code: 90 90 90 90 eb 1e 0f 1f 00 48 89 f8 48 89 d1 48 c1 e9 03 83 e2 07 f3 48 a5 89 d1 f3 a4 c3 66 0f 1f 44 00 00 48 89 f8 48 89 d1 <f3> a4 c3 0f 1f 80 00 00 00 00 48 89 f8 48 83 fa 20 72 7e 40 38 fe         
Jan 17 09:43:36 FNM00183301763-A kernel: RSP: 0018:ffffc90007bc3c70 EFLAGS: 00010206
Jan 17 09:43:36 FNM00183301763-A kernel: RAX: 34e40d75735a3225 RBX: 0000000000000400 RCX: 0000000000000400
Jan 17 09:43:36 FNM00183301763-A kernel: RDX: 0000000000000400 RSI: ffff8887f03368ca RDI: 34e40d75735a3225
Jan 17 09:43:36 FNM00183301763-A kernel: RBP: ffff88884ead9d60 R08: ffff8888b53e0530 R09: ffff889789776b4c
Jan 17 09:43:36 FNM00183301763-A kernel: R10: ffff8897897766c8 R11: ffff8887f03368ca R12: 0000000000000400
Jan 17 09:43:36 FNM00183301763-A kernel: R13: 0000000000000400 R14: ffff8887f0336cca R15: 0000000000000000
Jan 17 09:43:36 FNM00183301763-A kernel: FS:  0000000000000000(0000) GS:ffff8897dfe80000(0000) knlGS:0000000000000000
Jan 17 09:43:36 FNM00183301763-A kernel: CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
Jan 17 09:43:36 FNM00183301763-A kernel: CR2: 00007f592924d890 CR3: 000000000220a002 CR4: 00000000007606e0
Jan 17 09:43:36 FNM00183301763-A kernel: DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
Jan 17 09:43:36 FNM00183301763-A kernel: DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
Jan 17 09:43:36 FNM00183301763-A kernel: PKRU: 55555554
Jan 17 09:43:36 FNM00183301763-A kernel: Call Trace:
Jan 17 09:43:36 FNM00183301763-A kernel:  _copy_to_iter+0x333/0x3d0
Jan 17 09:43:36 FNM00183301763-A kernel:  ? tcp_write_xmit+0x403/0xfe0
Jan 17 09:43:36 FNM00183301763-A kernel:  skb_copy_datagram_iter+0x7b/0x260
Jan 17 09:43:36 FNM00183301763-A kernel:  tcp_recvmsg+0x238/0xc90
Jan 17 09:43:36 FNM00183301763-A kernel:  ? tcp_sendpage_locked+0x44/0x60
Jan 17 09:43:36 FNM00183301763-A kernel:  ? __local_bh_enable_ip+0x60/0x70
Jan 17 09:43:36 FNM00183301763-A kernel:  ? tcp_sendpage+0x41/0x50
Jan 17 09:43:36 FNM00183301763-A kernel:  inet_recvmsg+0x5b/0xd0
Jan 17 09:43:36 FNM00183301763-A kernel:  nvmet_tcp_io_work+0x116/0xb40 [nvmet_tcp]
Jan 17 09:43:36 FNM00183301763-A kernel:  process_one_work+0x206/0x400
Jan 17 09:43:36 FNM00183301763-A kernel:  worker_thread+0x2d/0x3e0
Jan 17 09:43:36 FNM00183301763-A kernel:  ? process_one_work+0x400/0x400
Jan 17 09:43:36 FNM00183301763-A kernel:  kthread+0x112/0x130
Jan 17 09:43:36 FNM00183301763-A kernel:  ? kthread_bind+0x20/0x20
Jan 17 09:43:36 FNM00183301763-A kernel:  ret_from_fork+0x1f/0x40


-----Original Message-----
From: Sagi Grimberg <sagi at grimberg.me> 
Sent: Saturday, 16 January 2021 3:19
To: Grupi, Elad; linux-nvme at lists.infradead.org
Subject: Re: [PATCH] nvme-tcp: fix a segmentation fault during io parsing error


[EXTERNAL EMAIL] 


>> This was a silly typo, did you check if it addressed your issue when you applied the needed change?
> 
> Yes. We applied the needed change before testing your patch, but still had kernel panic on recv flow when we had unread inline data on the socket.


Can you share the stack trace?

From chapman6235 at comcast.net  Sun Jan 17 13:58:34 2021
From: chapman6235 at comcast.net (Bradley Chapman)
Date: Sun, 17 Jan 2021 13:58:34 -0500
Subject: Problem with SPCC 256GB NVMe 1.3 drive - refcount_t: underflow;
 use-after-free.
Message-ID: <f50bc59c-db11-bb44-55be-7b9db1119872@comcast.net>

All,

I recently plugged a 256GB SPCC NVMe 1.3 drive into the secondary slot 
on my Asus X570-P motherboard, running a Ryzen 5 3600 CPU. After 
partitioning and formatting the drive, it is detected thusly by the 
5.9.15 and 5.10.6 kernels:

[    1.653074] nvme nvme1: pci function 0000:04:00.0
[    1.657181] nvme nvme1: missing or invalid SUBNQN field.
[    1.662294] nvme nvme1: allocated 64 MiB host memory buffer.
[    1.663105] nvme nvme1: 15/0/0 default/read/poll queues
[    1.665815]  nvme1n1: p1

However, any I/O to the drive (including mounting its filesystem) causes 
the following errors to appear in the dmesg. These errors occur with 
both the 5.9.15 kernel and the 5.10.6 kernel, and with X570-P BIOS 
version 1406 and version 3001. I have modified the BIOS settings to 
specify that a GEN 3 device is plugged into the M.2_2 slot instead of 
allowing the BIOS to auto-detect the drive.

[ 2745.659502] refcount_t: underflow; use-after-free.
[ 2745.659510] WARNING: CPU: 2 PID: 0 at lib/refcount.c:28 
refcount_warn_saturate+0xab/0xf0
[ 2745.659510] Modules linked in: rfcomm(E) cmac(E) bnep(E) 
binfmt_misc(E) nls_ascii(E) nls_cp437(E) vfat(E) fat(E) uas(E) 
usb_storage(E) btusb(E) btrtl(E) crct10dif_pclmul(E) btbcm(E) 
crc32_pclmul(E) btintel(E) ghash_clmulni_intel(E) bluetooth(E) rfkill(E) 
aesni_intel(E) crypto_simd(E) cryptd(E) glue_helper(E) efi_pstore(E) 
jitterentropy_rng(E) drbg(E) ccp(E) ansi_cprng(E) ecdh_generic(E) ecc(E) 
acpi_cpufreq(E) nft_counter(E) efivarfs(E) crc32c_intel(E)
[ 2745.659527] CPU: 2 PID: 0 Comm: swapper/2 Tainted: G            E 
5.10.6-BET #1
[ 2745.659528] Hardware name: System manufacturer System Product 
Name/PRIME X570-P, BIOS 3001 12/04/2020
[ 2745.659529] RIP: 0010:refcount_warn_saturate+0xab/0xf0
[ 2745.659530] Code: 05 af d2 72 01 01 e8 7a 06 87 00 0f 0b c3 80 3d 9d 
d2 72 01 00 75 90 48 c7 c7 78 60 44 af c6 05 8d d2 72 01 01 e8 5b 06 87 
00 <0f> 0b c3 80 3d 7c d2 72 01 00 0f 85 6d ff ff ff 48 c7 c7 d0 60 44
[ 2745.659531] RSP: 0018:ffffaf1880298f30 EFLAGS: 00010086
[ 2745.659532] RAX: 0000000000000000 RBX: ffff9873cf3bc300 RCX: 
0000000000000027
[ 2745.659533] RDX: 0000000000000027 RSI: ffff987acea92e80 RDI: 
ffff987acea92e88
[ 2745.659533] RBP: ffff9873d0e661f0 R08: 0000000000000000 R09: 
c0000000ffffdfff
[ 2745.659534] R10: ffffaf1880298d50 R11: ffffaf1880298d48 R12: 
0000000000000001
[ 2745.659534] R13: ffff9873d0f98580 R14: ffff9873cdf8ac00 R15: 
0000000000000000
[ 2745.659535] FS:  0000000000000000(0000) GS:ffff987acea80000(0000) 
knlGS:0000000000000000
[ 2745.659536] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 2745.659536] CR2: 00005588763902c8 CR3: 0000000107248000 CR4: 
0000000000350ee0
[ 2745.659537] Call Trace:
[ 2745.659538]  <IRQ>
[ 2745.659541]  nvme_irq+0x104/0x190
[ 2745.659543]  __handle_irq_event_percpu+0x2e/0xd0
[ 2745.659545]  handle_irq_event_percpu+0x33/0x80
[ 2745.659545]  handle_irq_event+0x39/0x70
[ 2745.659547]  handle_edge_irq+0x7c/0x1a0
[ 2745.659549]  asm_call_irq_on_stack+0x12/0x20
[ 2745.659549]  </IRQ>
[ 2745.659551]  common_interrupt+0xd7/0x160
[ 2745.659552]  asm_common_interrupt+0x1e/0x40
[ 2745.659554] RIP: 0010:cpuidle_enter_state+0xd2/0x2e0
[ 2745.659555] Code: e8 93 22 6a ff 31 ff 49 89 c5 e8 29 2c 6a ff 45 84 
ff 74 12 9c 58 f6 c4 02 0f 85 c4 01 00 00 31 ff e8 a2 d8 6f ff fb 45 85 
f6 <0f> 88 c9 00 00 00 49 63 ce be 68 00 00 00 4c 2b 2c 24 48 89 ca 48
[ 2745.659556] RSP: 0018:ffffaf188014fe80 EFLAGS: 00000202
[ 2745.659557] RAX: ffff987acea9ce00 RBX: 0000000000000002 RCX: 
000000000000001f
[ 2745.659557] RDX: 0000027f460f1f90 RSI: 00000000239f5229 RDI: 
0000000000000000
[ 2745.659558] RBP: ffff9873c1a4e800 R08: 0000000000000002 R09: 
000000000001c600
[ 2745.659558] R10: 0000090da145abf0 R11: ffff987acea9be24 R12: 
ffffffffaf6d38e0
[ 2745.659559] R13: 0000027f460f1f90 R14: 0000000000000002 R15: 
0000000000000000
[ 2745.659561]  cpuidle_enter+0x30/0x50
[ 2745.659562]  do_idle+0x24f/0x290
[ 2745.659564]  cpu_startup_entry+0x1b/0x20
[ 2745.659566]  start_secondary+0x10b/0x150
[ 2745.659567]  secondary_startup_64_no_verify+0xb0/0xbb
[ 2745.659569] ---[ end trace be84281f034198f3 ]---
[ 2776.138874] nvme nvme1: I/O 414 QID 3 timeout, aborting
[ 2776.138886] nvme nvme1: I/O 415 QID 3 timeout, aborting
[ 2776.138891] nvme nvme1: I/O 416 QID 3 timeout, aborting
[ 2776.138895] nvme nvme1: I/O 417 QID 3 timeout, aborting
[ 2776.138912] nvme nvme1: Abort status: 0x0
[ 2776.138921] nvme nvme1: I/O 428 QID 3 timeout, aborting
[ 2776.138922] nvme nvme1: Abort status: 0x0
[ 2776.138925] nvme nvme1: Abort status: 0x0
[ 2776.138974] nvme nvme1: Abort status: 0x0
[ 2776.138977] nvme nvme1: Abort status: 0x0
[ 2806.346792] nvme nvme1: I/O 414 QID 3 timeout, reset controller
[ 2806.363566] nvme nvme1: 15/0/0 default/read/poll queues
[ 2836.554298] nvme nvme1: I/O 415 QID 3 timeout, disable controller
[ 2836.672064] blk_update_request: I/O error, dev nvme1n1, sector 16350 
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[ 2836.672072] blk_update_request: I/O error, dev nvme1n1, sector 16093 
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[ 2836.672074] blk_update_request: I/O error, dev nvme1n1, sector 15836 
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[ 2836.672076] blk_update_request: I/O error, dev nvme1n1, sector 15579 
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[ 2836.672078] blk_update_request: I/O error, dev nvme1n1, sector 15322 
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[ 2836.672080] blk_update_request: I/O error, dev nvme1n1, sector 15065 
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[ 2836.672082] blk_update_request: I/O error, dev nvme1n1, sector 14808 
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[ 2836.672083] blk_update_request: I/O error, dev nvme1n1, sector 14551 
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[ 2836.672085] blk_update_request: I/O error, dev nvme1n1, sector 14294 
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[ 2836.672087] blk_update_request: I/O error, dev nvme1n1, sector 14037 
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[ 2836.672121] nvme nvme1: failed to mark controller live state
[ 2836.672123] nvme nvme1: Removing after probe failure status: -19
[ 2836.689016] Aborting journal on device dm-0-8.
[ 2836.689024] Buffer I/O error on dev dm-0, logical block 25198592, 
lost sync page write
[ 2836.689027] JBD2: Error -5 detected when updating journal superblock 
for dm-0-8.

[ 2836.723821] percpu ref (hd_struct_free) <= 0 (-28) after switching to 
atomic
[ 2836.723828] WARNING: CPU: 8 PID: 0 at lib/percpu-refcount.c:196 
percpu_ref_switch_to_atomic_rcu+0x139/0x140
[ 2836.723828] Modules linked in: rfcomm(E) cmac(E) bnep(E) 
binfmt_misc(E) nls_ascii(E) nls_cp437(E) vfat(E) fat(E) uas(E) 
usb_storage(E) btusb(E) btrtl(E) crct10dif_pclmul(E) btbcm(E) 
crc32_pclmul(E) btintel(E) ghash_clmulni_intel(E) bluetooth(E) rfkill(E) 
aesni_intel(E) crypto_simd(E) cryptd(E) glue_helper(E) efi_pstore(E) 
jitterentropy_rng(E) drbg(E) ccp(E) ansi_cprng(E) ecdh_generic(E) ecc(E) 
acpi_cpufreq(E) nft_counter(E) efivarfs(E) crc32c_intel(E)
[ 2836.723844] CPU: 8 PID: 0 Comm: swapper/8 Tainted: G        W   E 
5.10.6-BET #1
[ 2836.723845] Hardware name: System manufacturer System Product 
Name/PRIME X570-P, BIOS 3001 12/04/2020
[ 2836.723847] RIP: 0010:percpu_ref_switch_to_atomic_rcu+0x139/0x140
[ 2836.723848] Code: 80 3d f9 f0 72 01 00 0f 85 52 ff ff ff 49 8b 54 24 
e0 49 8b 74 24 e8 48 c7 c7 88 5f 44 af c6 05 db f0 72 01 01 e8 ad 24 87 
00 <0f> 0b e9 2e ff ff ff 41 55 49 89 f5 41 54 55 48 89 fd 53 48 83 ec
[ 2836.723849] RSP: 0018:ffffaf18803a0f20 EFLAGS: 00010282
[ 2836.723850] RAX: 0000000000000000 RBX: 7fffffffffffffe3 RCX: 
0000000000000027
[ 2836.723850] RDX: 0000000000000027 RSI: ffff987acec12e80 RDI: 
ffff987acec12e88
[ 2836.723851] RBP: 0000369db0c0e3c8 R08: 0000000000000000 R09: 
c0000000ffffdfff
[ 2836.723851] R10: ffffaf18803a0d40 R11: ffffaf18803a0d38 R12: 
ffff9873c0bbbda0
[ 2836.723852] R13: ffffffffaf765f10 R14: 0000000000000202 R15: 
ffffffffaf6060c0
[ 2836.723853] FS:  0000000000000000(0000) GS:ffff987acec00000(0000) 
knlGS:0000000000000000
[ 2836.723853] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 2836.723854] CR2: 0000558899b414c0 CR3: 0000000101cd2000 CR4: 
0000000000350ee0
[ 2836.723854] Call Trace:
[ 2836.723855]  <IRQ>
[ 2836.723859]  rcu_core+0x196/0x420
[ 2836.723862]  __do_softirq+0xc9/0x214
[ 2836.723863]  asm_call_irq_on_stack+0x12/0x20
[ 2836.723864]  </IRQ>
[ 2836.723866]  do_softirq_own_stack+0x31/0x40
[ 2836.723867]  irq_exit_rcu+0x9a/0xa0
[ 2836.723869]  sysvec_apic_timer_interrupt+0x2c/0x80
[ 2836.723870]  asm_sysvec_apic_timer_interrupt+0x12/0x20
[ 2836.723872] RIP: 0010:cpuidle_enter_state+0xd2/0x2e0
[ 2836.723873] Code: e8 93 22 6a ff 31 ff 49 89 c5 e8 29 2c 6a ff 45 84 
ff 74 12 9c 58 f6 c4 02 0f 85 c4 01 00 00 31 ff e8 a2 d8 6f ff fb 45 85 
f6 <0f> 88 c9 00 00 00 49 63 ce be 68 00 00 00 4c 2b 2c 24 48 89 ca 48
[ 2836.723874] RSP: 0018:ffffaf188017fe80 EFLAGS: 00000202
[ 2836.723874] RAX: ffff987acec1ce00 RBX: 0000000000000002 RCX: 
000000000000001f
[ 2836.723875] RDX: 0000029479ea3f98 RSI: 00000000239f5229 RDI: 
0000000000000000
[ 2836.723875] RBP: ffff9873c1a4ec00 R08: 0000000000000002 R09: 
000000000001c600
[ 2836.723876] R10: 00000959d0ea6498 R11: ffff987acec1be24 R12: 
ffffffffaf6d38e0
[ 2836.723876] R13: 0000029479ea3f98 R14: 0000000000000002 R15: 
0000000000000000
[ 2836.723878]  cpuidle_enter+0x30/0x50
[ 2836.723880]  do_idle+0x24f/0x290
[ 2836.723882]  cpu_startup_entry+0x1b/0x20
[ 2836.723884]  start_secondary+0x10b/0x150
[ 2836.723885]  secondary_startup_64_no_verify+0xb0/0xbb
[ 2836.723887] ---[ end trace be84281f034198f4 ]---

After these errors are generated, the device becomes inaccessible and 
unmounting its filesystem (which does not hang in D state) generates 
additional errors:

[ 2868.181018] Buffer I/O error on dev dm-0, logical block 0, lost sync 
page write
[ 2868.181022] EXT4-fs (dm-0): I/O error while writing superblock

After the filesystem is unmounted the device no longer appears in the 
output of lsblk(8) and its device node(s) disappear after the kernel 
removes the device. Prior to the I/O failures, the nvme error-log 
command returns no error entries for any of the 64 log entries present.

nvme fw-log and nvme smart-log return the following output:

Firmware Log for device:nvme1
afi  : 0x20

Smart Log for NVME device:nvme1 namespace-id:ffffffff
critical_warning                    : 0
temperature                         : 48 C
available_spare                     : 100%
available_spare_threshold           : 10%
percentage_used                     : 0%
data_units_read                     : 234
data_units_written                  : 2,149
host_read_commands                  : 4,202
host_write_commands                 : 421,917
controller_busy_time                : 0
power_cycles                        : 7
power_on_hours                      : 11
unsafe_shutdowns                    : 0
media_errors                        : 0
num_err_log_entries                 : 0
Warning Temperature Time            : 0
Critical Composite Temperature Time : 0
Temperature Sensor 1                : 48 C
Thermal Management T1 Trans Count   : 0
Thermal Management T2 Trans Count   : 0
Thermal Management T1 Total Time    : 0
Thermal Management T2 Total Time    : 0

I've checked the kernel change logs and I know that the refcount_t error 
has been occurring in other kernel subsystems and was subsequently fixed 
in recent kernel point releases, so I will be trying to reproduce this 
error with the most recent 5.10 and 5.11-rc kernels.

Any suggestions on what else to try next?

Thanks!

Brad


From lengchao at huawei.com  Sun Jan 17 22:22:16 2021
From: lengchao at huawei.com (Chao Leng)
Date: Mon, 18 Jan 2021 11:22:16 +0800
Subject: [PATCH v2 4/6] nvme-rdma: avoid IO error and repeated request
 completion
In-Reply-To: <4ff22d33-12fa-1f70-3606-54821f314c45@grimberg.me>
References: <20210107033149.15701-1-lengchao@huawei.com>
 <20210107033149.15701-5-lengchao@huawei.com>
 <07e41b4f-914a-11e8-5638-e2d6408feb3f@grimberg.me>
 <7b12be41-0fcd-5a22-0e01-8cd4ac9cde5b@huawei.com>
 <a3404c7d-ccc8-0d55-d4a8-fc15107c90e6@grimberg.me>
 <695b6839-5333-c342-2189-d7aaeba797a7@huawei.com>
 <4ff22d33-12fa-1f70-3606-54821f314c45@grimberg.me>
Message-ID: <0b5c8e31-8dc2-994a-1710-1b1be07549c9@huawei.com>



On 2021/1/16 9:18, Sagi Grimberg wrote:
> 
>>>>>> When a request is queued failed, blk_status_t is directly returned
>>>>>> to the blk-mq. If blk_status_t is not BLK_STS_RESOURCE,
>>>>>> BLK_STS_DEV_RESOURCE, BLK_STS_ZONE_RESOURCE, blk-mq call
>>>>>> blk_mq_end_request to complete the request with BLK_STS_IOERR.
>>>>>> In two scenarios, the request should be retried and may succeed.
>>>>>> First, if work with nvme multipath, the request may be retried
>>>>>> successfully in another path, because the error is probably related to
>>>>>> the path. Second, if work without multipath software, the request may
>>>>>> be retried successfully after error recovery.
>>>>>> If the request is complete with BLK_STS_IOERR in blk_mq_dispatch_rq_list.
>>>>>> The state of request may be changed to MQ_RQ_IN_FLIGHT. If free the
>>>>>> request asynchronously such as in nvme_submit_user_cmd, in extreme
>>>>>> scenario the request will be repeated freed in tear down.
>>>>>> If a non-resource error occurs in queue_rq, should directly call
>>>>>> nvme_complete_rq to complete request and set the state of request to
>>>>>> MQ_RQ_COMPLETE. nvme_complete_rq will decide to retry, fail over or end
>>>>>> the request.
>>>>>>
>>>>>> Signed-off-by: Chao Leng <lengchao at huawei.com>
>>>>>> ---
>>>>>> ? drivers/nvme/host/rdma.c | 2 +-
>>>>>> ? 1 file changed, 1 insertion(+), 1 deletion(-)
>>>>>>
>>>>>> diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
>>>>>> index df9f6f4549f1..4a89bf44ecdc 100644
>>>>>> --- a/drivers/nvme/host/rdma.c
>>>>>> +++ b/drivers/nvme/host/rdma.c
>>>>>> @@ -2093,7 +2093,7 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
>>>>>> ? unmap_qe:
>>>>>> ????? ib_dma_unmap_single(dev, req->sqe.dma, sizeof(struct nvme_command),
>>>>>> ????????????????? DMA_TO_DEVICE);
>>>>>> -??? return ret;
>>>>>> +??? return nvme_try_complete_failed_req(rq, ret);
>>>>>
>>>>> I don't understand this. There are errors that may not be related to
>>>>> anything that is pathing related (sw bug, memory leak, mapping error,
>>>>> etc, etc) why should we return this one-shot error?
>>>> Although fail over retry is not required, if we return the error to
>>>> blk-mq, a low probability crash may happen. because blk-mq do not set
>>>> the state of request to MQ_RQ_COMPLETE before complete the request,
>>>> the request may be freed asynchronously such as in nvme_submit_user_cmd.
>>>> If race with error recovery, request double completion may happens.
>>>
>>> Then fix that, don't work around it.
>> I'm not trying to work around it. The purpose of this is to solve
>> the problem of nvme native multipathing at the same time.
> 
> Please explain how this is an nvme-multipath issue?
> 
>>>
>>>>
>>>> So we can not return the error to blk-mq if the blk_status_t is not
>>>> BLK_STS_RESOURCE, BLK_STS_DEV_RESOURCE, BLK_STS_ZONE_RESOURCE.
>>>
>>> This is not something we should be handling in nvme. block drivers
>>> should be able to fail queue_rq, and this all should live in the
>>> block layer.
>> Of course, it is also an idea to repair the block drivers directly.
>> However, block layer is unaware of nvme native multipathing,
> 
> Nor it should be
> 
>> will cause the request return error which should be avoided.
> 
> Not sure I understand..
> requests should failover for path related errors,
> what queue_rq errors are expected to be failed over from your
> perspective?
Although fail over for only path related errors is the best choice, it's
almost impossible to achieve.
The probability of non-path-related errors is very low. Although these
errors do not require fail over retry, the cost of fail over retry
is complete the request with error delay a bit long time(retry several
times). It's not the best choice, but I think it's acceptable, because
HBA driver does not have path-related error codes but only general error
codes. It is difficult to identify whether the general error codes are
path-related.
> 
>> The scenario: use two HBAs for nvme native multipath, and then one HBA
>> fault,
> 
> What is the specific error the driver sees?
The path related error code is closely related to HBA driver
implementation. In general it is EIO. I don't think it's a good idea to
assume what general error code the driver returns in the event of a path
error.
> 
>> the blk_status_t of queue_rq is BLK_STS_IOERR, blk-mq will call
>> blk_mq_end_request to complete the request which bypass name native
>> multipath. We expect the request fail over to normal HBA, but the request
>> is directly completed with BLK_STS_IOERR.
>> The two scenarios can be fixed by directly completing the request in queue_rq.
> Well, certainly this one-shot always return 0 and complete the command
> with HOST_PATH error is not a good approach IMO
So what's the better option? Just complete the request with host path
error for non-ENOMEM and EAGAIN returned by the HBA driver?


From Chaitanya.Kulkarni at wdc.com  Sun Jan 17 23:36:01 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Mon, 18 Jan 2021 04:36:01 +0000
Subject: Problem with SPCC 256GB NVMe 1.3 drive - refcount_t: underflow;
 use-after-free.
References: <f50bc59c-db11-bb44-55be-7b9db1119872@comcast.net>
Message-ID: <BYAPR04MB49659C0F0F0E11D166B31E0586A40@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/17/21 11:05 AM, Bradley Chapman wrote:
> [ 2836.554298] nvme nvme1: I/O 415 QID 3 timeout, disable controller
> [ 2836.672064] blk_update_request: I/O error, dev nvme1n1, sector 16350 
> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
> [ 2836.672072] blk_update_request: I/O error, dev nvme1n1, sector 16093 
> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
> [ 2836.672074] blk_update_request: I/O error, dev nvme1n1, sector 15836 
> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
> [ 2836.672076] blk_update_request: I/O error, dev nvme1n1, sector 15579 
> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
> [ 2836.672078] blk_update_request: I/O error, dev nvme1n1, sector 15322 
> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
> [ 2836.672080] blk_update_request: I/O error, dev nvme1n1, sector 15065 
> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
> [ 2836.672082] blk_update_request: I/O error, dev nvme1n1, sector 14808 
> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
> [ 2836.672083] blk_update_request: I/O error, dev nvme1n1, sector 14551 
> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
> [ 2836.672085] blk_update_request: I/O error, dev nvme1n1, sector 14294 
> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
> [ 2836.672087] blk_update_request: I/O error, dev nvme1n1, sector 14037 
> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
> [ 2836.672121] nvme nvme1: failed to mark controller live state
> [ 2836.672123] nvme nvme1: Removing after probe failure status: -19
> [ 2836.689016] Aborting journal on device dm-0-8.
> [ 2836.689024] Buffer I/O error on dev dm-0, logical block 25198592, 
> lost sync page write
> [ 2836.689027] JBD2: Error -5 detected when updating journal superblock 
> for dm-0-8.
Without the knowledge of fs mount/format command I can only suspect that
super
block zeroing issued with write-zeroes request is translated into
REQ_OP_WRITE_ZEROES which controller is not able to process resulting in
the error. This analysis maybe wrong.

Can you please share following details :-

nvme id-ns /dev/nvme0n1 -H (we are interested in oncs part here)

Also for above device what is the value for the queue block write-zeroes

parameter that is present in the
/sys/block/<nvmeXnY>/queue/write_zeroes_max_bytes ?

You can also try blkdiscard -z 0 -l 1024 /dev/<nvmeXnY> to see if the
problem is with
write zeroes.

Also can you please also try the latest nvme tree branch nvme-5.11 ?



From hch at lst.de  Mon Jan 18 12:40:51 2021
From: hch at lst.de (Christoph Hellwig)
Date: Mon, 18 Jan 2021 18:40:51 +0100
Subject: [PATCH V3 3/3] nvme: retry commands based on ACRE flag
In-Reply-To: <20210115182602.GA2822@localhost.localdomain>
References: <20210114133110.20779-1-minwoo.im.dev@gmail.com>
 <20210114133110.20779-4-minwoo.im.dev@gmail.com>
 <20210115170412.GA1515933@dhcp-10-100-145-180.wdc.com>
 <20210115182602.GA2822@localhost.localdomain>
Message-ID: <20210118174051.GA8542@lst.de>

On Sat, Jan 16, 2021 at 03:26:02AM +0900, Minwoo Im wrote:
> > I am not sure we should ignore the FAILFAST for non-path errors. If we
> > need retryable admin commands, we should let the driver provide a way
> > for callers to dispatch requests without that flag.
> 
> Understood.  I thought the opposite way about FAILFAST in case with
> acre, if device is enabled with acre, all commands would be retried
> regardless to FAILFAST...  Thanks for pointing that out!
> 
> How do you think which one is right choice to go with if a user-space
> application(e.g., nvme-cli) wants a command to be retired in case of
> ACRE && Error && !DNR:
> 
>   - User-space application should figure out !DNR and retry the command.
>     (Maybe we are not able to easily figure out exact status code from
>     the user-space application by the return value).
> 
>   - Driver should retry the command right before putting result up to
>     the user-space even it's a FAILFAST request.
> 
> Thanks,

We could come up with a version of the ioctls that use the normal
retry mechanisms.  nvme_passthru_cmd64 has two reserved fields we
could use for UAPI flags like this.


From hch at lst.de  Mon Jan 18 12:49:13 2021
From: hch at lst.de (Christoph Hellwig)
Date: Mon, 18 Jan 2021 18:49:13 +0100
Subject: [PATCH v2 4/6] nvme-rdma: avoid IO error and repeated request
 completion
In-Reply-To: <0b5c8e31-8dc2-994a-1710-1b1be07549c9@huawei.com>
References: <20210107033149.15701-1-lengchao@huawei.com>
 <20210107033149.15701-5-lengchao@huawei.com>
 <07e41b4f-914a-11e8-5638-e2d6408feb3f@grimberg.me>
 <7b12be41-0fcd-5a22-0e01-8cd4ac9cde5b@huawei.com>
 <a3404c7d-ccc8-0d55-d4a8-fc15107c90e6@grimberg.me>
 <695b6839-5333-c342-2189-d7aaeba797a7@huawei.com>
 <4ff22d33-12fa-1f70-3606-54821f314c45@grimberg.me>
 <0b5c8e31-8dc2-994a-1710-1b1be07549c9@huawei.com>
Message-ID: <20210118174913.GA8700@lst.de>

On Mon, Jan 18, 2021 at 11:22:16AM +0800, Chao Leng wrote:
>> Well, certainly this one-shot always return 0 and complete the command
>> with HOST_PATH error is not a good approach IMO
> So what's the better option? Just complete the request with host path
> error for non-ENOMEM and EAGAIN returned by the HBA driver?

what HBA driver?


From hch at lst.de  Mon Jan 18 12:58:58 2021
From: hch at lst.de (Christoph Hellwig)
Date: Mon, 18 Jan 2021 18:58:58 +0100
Subject: [PATCH V4 1/4] nvmet: set right status on error in id-ns handler
In-Reply-To: <20210114013354.33946-2-chaitanya.kulkarni@wdc.com>
References: <20210114013354.33946-1-chaitanya.kulkarni@wdc.com>
 <20210114013354.33946-2-chaitanya.kulkarni@wdc.com>
Message-ID: <20210118175858.GA9901@lst.de>

Thanks,

applied to nvme-5.11.


From hch at lst.de  Mon Jan 18 12:59:11 2021
From: hch at lst.de (Christoph Hellwig)
Date: Mon, 18 Jan 2021 18:59:11 +0100
Subject: [PATCH v2 0/2] avoid request double completion for concurrent
 nvme_rdma(tcp)_timeout
In-Reply-To: <20210114090926.12109-1-lengchao@huawei.com>
References: <20210114090926.12109-1-lengchao@huawei.com>
Message-ID: <20210118175911.GB9901@lst.de>

Thanks,

applied to nvme-5.11.


From hch at lst.de  Mon Jan 18 12:59:26 2021
From: hch at lst.de (Christoph Hellwig)
Date: Mon, 18 Jan 2021 18:59:26 +0100
Subject: [PATCH v3] nvme: Check the PRINFO bit and the Metadata size
 before deciding the host buffer length
In-Reply-To: <20210115015507.45615-1-revanth.rajashekar@intel.com>
References: <20210115015507.45615-1-revanth.rajashekar@intel.com>
Message-ID: <20210118175926.GC9901@lst.de>

Thanks,

applied to nvme-5.11.


From hch at lst.de  Mon Jan 18 12:59:56 2021
From: hch at lst.de (Christoph Hellwig)
Date: Mon, 18 Jan 2021 18:59:56 +0100
Subject: [PATCH v2] nvme: allow use of cmb on v1.4 controllers
In-Reply-To: <20210115063046.274495-1-its@irrelevant.dk>
References: <20210115063046.274495-1-its@irrelevant.dk>
Message-ID: <20210118175956.GD9901@lst.de>

Thanks,

applied to nvme-5.11 with a little tweak to remove the cmbmsc local
variable and a comment explaining what is going on.


From hch at lst.de  Mon Jan 18 13:09:19 2021
From: hch at lst.de (Christoph Hellwig)
Date: Mon, 18 Jan 2021 19:09:19 +0100
Subject: [PATCH] nvme: refactor ns->ctrl by request
In-Reply-To: <20210113143627.787-1-minwoo.im.dev@gmail.com>
References: <20210113143627.787-1-minwoo.im.dev@gmail.com>
Message-ID: <20210118180919.GA10689@lst.de>

Applied to nvme-5.12, thanks.


From hch at lst.de  Mon Jan 18 13:09:30 2021
From: hch at lst.de (Christoph Hellwig)
Date: Mon, 18 Jan 2021 19:09:30 +0100
Subject: [PATCH V4 2/4] nvmet: remove extra variable in smart log nsid
In-Reply-To: <20210114013354.33946-3-chaitanya.kulkarni@wdc.com>
References: <20210114013354.33946-1-chaitanya.kulkarni@wdc.com>
 <20210114013354.33946-3-chaitanya.kulkarni@wdc.com>
Message-ID: <20210118180930.GB10689@lst.de>

Applied patches 2-3 to nvme-5.12, thanks.


From hch at lst.de  Mon Jan 18 13:09:36 2021
From: hch at lst.de (Christoph Hellwig)
Date: Mon, 18 Jan 2021 19:09:36 +0100
Subject: [PATCH 0/3 RESEND] few simple cleanups for nvme-tcp host
In-Reply-To: <20210114211526.86946-1-sagi@grimberg.me>
References: <20210114211526.86946-1-sagi@grimberg.me>
Message-ID: <20210118180936.GC10689@lst.de>

Applied to nvme-5.12, thanks.


From hch at lst.de  Mon Jan 18 13:19:42 2021
From: hch at lst.de (Christoph Hellwig)
Date: Mon, 18 Jan 2021 19:19:42 +0100
Subject: [PATCH V9 2/9] nvmet: add lba to sect conversion helpers
In-Reply-To: <20210112042623.6316-3-chaitanya.kulkarni@wdc.com>
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-3-chaitanya.kulkarni@wdc.com>
Message-ID: <20210118181942.GA11082@lst.de>

Applied to nvme-5.12.


From hch at lst.de  Mon Jan 18 13:21:05 2021
From: hch at lst.de (Christoph Hellwig)
Date: Mon, 18 Jan 2021 19:21:05 +0100
Subject: [PATCH V9 3/9] nvmet: add NVM command set identifier support
In-Reply-To: <BYAPR04MB4965017878A807316A0A1BBA86A90@BYAPR04MB4965.namprd04.prod.outlook.com>
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-4-chaitanya.kulkarni@wdc.com>
 <20210112072715.GB24155@lst.de>
 <BYAPR04MB4965017878A807316A0A1BBA86A90@BYAPR04MB4965.namprd04.prod.outlook.com>
Message-ID: <20210118182105.GB11082@lst.de>

On Wed, Jan 13, 2021 at 04:16:51AM +0000, Chaitanya Kulkarni wrote:
> We advertise the support for command sets supported in
> nvmet_init_cap() -> ctrl->cap = (1ULL << 37). This results in
> nvme_enable_ctrl() setting the ctrl->ctrl_config -> NVME_CC_CSS_NVM.
> In current code in nvmet_start_ctrl() ->  nvmet_cc_css(ctrl->cc) != 0
> checks if value is not = 0 but doesn't use the macro used by the host.
> Above function does that also makes it helper that we use in the next
> patch where cc_css value is != 0 but NVME_CC_CSS_CSI with
> ctrl->cap set to 1ULL << 43.
> 
> With code flow in [1] above function is needed to make sure css value
> matches the value set by the host using the same macro in
> nvme_enable_ctrl() NVME_CC_CSS_NVM. Otherwise patch looks incomplete
> and adding check for the CSS NVM with CSS_CSI looks mixing up things
> to me.
> 
> Are you okay with that ?

Yeah, we can probably include it in an overall multiple command sets
support patch.


From hch at lst.de  Mon Jan 18 13:25:15 2021
From: hch at lst.de (Christoph Hellwig)
Date: Mon, 18 Jan 2021 19:25:15 +0100
Subject: [PATCH V9 4/9] nvmet: add ZBD over ZNS backend support
In-Reply-To: <BL0PR04MB65145CE93F2AAF66158A3D71E7AA0@BL0PR04MB6514.namprd04.prod.outlook.com>
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-5-chaitanya.kulkarni@wdc.com>
 <20210112074805.GA24443@lst.de>
 <BL0PR04MB65145CE93F2AAF66158A3D71E7AA0@BL0PR04MB6514.namprd04.prod.outlook.com>
Message-ID: <20210118182515.GC11082@lst.de>

On Tue, Jan 12, 2021 at 07:52:27AM +0000, Damien Le Moal wrote:
> > 
> > I do not understand the logic here, given that NVMe does not have
> > conventional zones.
> 
> 512e SAS & SATA SMR drives (512B logical, 4K physical) are a big thing, and for
> these, all writes in sequential zones must be 4K aligned. So I suggested to
> Chaitanya to simply use the physical block size as the LBA size for the target
> to avoid weird IO errors that would not make sense in ZNS/NVMe world (e.g. 512B
> aligned write requests failing).

But in NVMe the physical block size exposes the atomic write unit, which
could be way too large.  ?f we want to do this cleanly we need to expose
a minimum sequential zone write alignment value in the block layer.


From hch at lst.de  Mon Jan 18 13:27:23 2021
From: hch at lst.de (Christoph Hellwig)
Date: Mon, 18 Jan 2021 19:27:23 +0100
Subject: [PATCH V9 4/9] nvmet: add ZBD over ZNS backend support
In-Reply-To: <BYAPR04MB4965CE08B1DE8BC36585991686A90@BYAPR04MB4965.namprd04.prod.outlook.com>
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-5-chaitanya.kulkarni@wdc.com>
 <20210112074805.GA24443@lst.de>
 <BYAPR04MB4965CE08B1DE8BC36585991686A90@BYAPR04MB4965.namprd04.prod.outlook.com>
Message-ID: <20210118182723.GD11082@lst.de>

On Wed, Jan 13, 2021 at 04:57:15AM +0000, Chaitanya Kulkarni wrote:
> >>  	/* command sets supported: NVMe command set: */
> >>  	ctrl->cap = (1ULL << 37);
> >> +	if (IS_ENABLED(CONFIG_BLK_DEV_ZONED))
> >> +		ctrl->cap |= (1ULL << 43);
> >>  	/* CC.EN timeout in 500msec units: */
> >>  	ctrl->cap |= (15ULL << 24);
> >>  	/* maximum queue entries supported: */
> > This needs to go into a separate patch for multiple command set support.
> > We can probably merge the CAP and CC bits with the CSI support, though.
> Do you mean previous patch ?

Yes.

> but we don't add handlers non-default I/O
> command set until this patch..

No, bit 43 just means the TP to support multiple comman sets is supported.
That infrastructure can be used even by controllers only supporting the
NVM command set.

> > bdev_is_zoned should be probably stubbed out for !CONFIG_BLK_DEV_ZONED
> > these days.
> Are you saying something like following in the prep patch ?or should
> just remove
> theIS_ENABLED(CONFIG_BLK_DEV_ZONED)part in above if?
> 
> diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
> index 028ccc9bdf8d..124086c1a0ba 100644
> --- a/include/linux/blkdev.h
> +++ b/include/linux/blkdev.h
> @@ -1570,6 +1570,9 @@ static inline bool bdev_is_zoned(struct
> block_device *bdev)
>  {
>         struct request_queue *q = bdev_get_queue(bdev);
>  
> +       if (!IS_ENABLED(CONFIG_BLK_DEV_ZONED))
> +               return false;
> +
>         if (q)
>                 return blk_queue_is_zoned(q);

blk_queue_is_zoned calls blk_queue_zoned_model, which is stubbed out
already.  So no extra work should be required.

> 	/*
> 	 * For ZBC and ZAC devices, writes into sequential zones must be aligned
> 	 * to the device physical block size. So use this value as the *physical*
> 	 * block size to avoid errors.
> 	 */

See my reply to Damien.


From hch at lst.de  Mon Jan 18 13:28:03 2021
From: hch at lst.de (Christoph Hellwig)
Date: Mon, 18 Jan 2021 19:28:03 +0100
Subject: [PATCH V9 5/9] nvmet: add bio get helper for different backends
In-Reply-To: <BYAPR04MB4965361DC74566BD26E3DC7B86A90@BYAPR04MB4965.namprd04.prod.outlook.com>
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-6-chaitanya.kulkarni@wdc.com>
 <20210112073315.GA24288@lst.de>
 <BYAPR04MB4965361DC74566BD26E3DC7B86A90@BYAPR04MB4965.namprd04.prod.outlook.com>
Message-ID: <20210118182803.GE11082@lst.de>

On Wed, Jan 13, 2021 at 05:03:05AM +0000, Chaitanya Kulkarni wrote:
> On 1/11/21 23:33, Christoph Hellwig wrote:
> > I'm not a huge fan of this helper, especially as it sets an end_io
> > callback only for the allocated case, which is a weird calling
> > convention.
> >
> 
> The patch has a right documentation and that end_io is needed
> for passthru case. To get rid of the weirdness I can remove
> passthru case and make itend_io assign to inline and non-inline bio
> to make it non-weired.
> 
> Since this eliminates exactly identical lines of the code in atleast two
> backend which we should try to use the helper in non-wried way.

I really do not like helper that just eliminate "duplicate lines" vs
encapsulating logic that makes sense one its own.


From its at irrelevant.dk  Mon Jan 18 13:29:10 2021
From: its at irrelevant.dk (Klaus Jensen)
Date: Mon, 18 Jan 2021 19:29:10 +0100
Subject: [PATCH v2] nvme: allow use of cmb on v1.4 controllers
In-Reply-To: <20210118175956.GD9901@lst.de>
References: <20210115063046.274495-1-its@irrelevant.dk>
 <20210118175956.GD9901@lst.de>
Message-ID: <YAXTdohFxR5J9hwY@apples.localdomain>

On Jan 18 18:59, Christoph Hellwig wrote:
> Thanks,
> 
> applied to nvme-5.11 with a little tweak to remove the cmbmsc local
> variable and a comment explaining what is going on.
> 

Sweet. Thanks!
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-nvme/attachments/20210118/d5716797/attachment.sig>

From hch at lst.de  Mon Jan 18 13:33:53 2021
From: hch at lst.de (Christoph Hellwig)
Date: Mon, 18 Jan 2021 19:33:53 +0100
Subject: [PATCH V9 6/9] nvmet: add bio init helper for different backends
In-Reply-To: <BYAPR04MB4965824B7DB93A26C625AAD586A90@BYAPR04MB4965.namprd04.prod.outlook.com>
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-7-chaitanya.kulkarni@wdc.com>
 <20210112073358.GB24288@lst.de>
 <BYAPR04MB4965824B7DB93A26C625AAD586A90@BYAPR04MB4965.namprd04.prod.outlook.com>
Message-ID: <20210118183353.GA11556@lst.de>

On Wed, Jan 13, 2021 at 05:04:49AM +0000, Chaitanya Kulkarni wrote:
> On 1/11/21 23:34, Christoph Hellwig wrote:
> > Nothing NVMe specific about this.  The helper also doesn't relaly contain
> > any logic either.
> >
> What is the preferable name ? just bio_init_fields() ?

We'll eventually need to replace bio_alloc with something initializing
the additional fields.  For now I'd just do nothing and skip the helper
for now.


From hch at lst.de  Mon Jan 18 13:34:37 2021
From: hch at lst.de (Christoph Hellwig)
Date: Mon, 18 Jan 2021 19:34:37 +0100
Subject: [PATCH V9 8/9] nvmet: add common I/O length check helper
In-Reply-To: <BYAPR04MB4965136E54EA80910B9ED43986A90@BYAPR04MB4965.namprd04.prod.outlook.com>
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-9-chaitanya.kulkarni@wdc.com>
 <20210112073503.GC24288@lst.de>
 <BYAPR04MB4965136E54EA80910B9ED43986A90@BYAPR04MB4965.namprd04.prod.outlook.com>
Message-ID: <20210118183437.GB11556@lst.de>

On Wed, Jan 13, 2021 at 05:07:16AM +0000, Chaitanya Kulkarni wrote:
> On 1/11/21 23:35, Christoph Hellwig wrote:
> > I can't say I like this helper.  The semantics are a little confusing,
> > not helped by the name.
> >
> Is it because of the name of the helper ? if so can you please suggest a
> name.
> Because all it has a same code repeated in the three backends and it really
> bothers me to see duplicate code, but that just me :P.

Also because it does two rather unrelated things.  Or in other words:
I don't think the helper helps the readability of the code.


From chapman6235 at comcast.net  Mon Jan 18 13:33:42 2021
From: chapman6235 at comcast.net (Bradley Chapman)
Date: Mon, 18 Jan 2021 13:33:42 -0500
Subject: Problem with SPCC 256GB NVMe 1.3 drive - refcount_t: underflow;
 use-after-free.
In-Reply-To: <BYAPR04MB49659C0F0F0E11D166B31E0586A40@BYAPR04MB4965.namprd04.prod.outlook.com>
References: <f50bc59c-db11-bb44-55be-7b9db1119872@comcast.net>
 <BYAPR04MB49659C0F0F0E11D166B31E0586A40@BYAPR04MB4965.namprd04.prod.outlook.com>
Message-ID: <a4c75497-d170-1e0f-8608-282231ff3a8e@comcast.net>

Good afternoon!

On 1/17/21 11:36 PM, Chaitanya Kulkarni wrote:
> On 1/17/21 11:05 AM, Bradley Chapman wrote:
>> [ 2836.554298] nvme nvme1: I/O 415 QID 3 timeout, disable controller
>> [ 2836.672064] blk_update_request: I/O error, dev nvme1n1, sector 16350
>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>> [ 2836.672072] blk_update_request: I/O error, dev nvme1n1, sector 16093
>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>> [ 2836.672074] blk_update_request: I/O error, dev nvme1n1, sector 15836
>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>> [ 2836.672076] blk_update_request: I/O error, dev nvme1n1, sector 15579
>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>> [ 2836.672078] blk_update_request: I/O error, dev nvme1n1, sector 15322
>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>> [ 2836.672080] blk_update_request: I/O error, dev nvme1n1, sector 15065
>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>> [ 2836.672082] blk_update_request: I/O error, dev nvme1n1, sector 14808
>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>> [ 2836.672083] blk_update_request: I/O error, dev nvme1n1, sector 14551
>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>> [ 2836.672085] blk_update_request: I/O error, dev nvme1n1, sector 14294
>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>> [ 2836.672087] blk_update_request: I/O error, dev nvme1n1, sector 14037
>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>> [ 2836.672121] nvme nvme1: failed to mark controller live state
>> [ 2836.672123] nvme nvme1: Removing after probe failure status: -19
>> [ 2836.689016] Aborting journal on device dm-0-8.
>> [ 2836.689024] Buffer I/O error on dev dm-0, logical block 25198592,
>> lost sync page write
>> [ 2836.689027] JBD2: Error -5 detected when updating journal superblock
>> for dm-0-8.
> Without the knowledge of fs mount/format command I can only suspect that
> super
> block zeroing issued with write-zeroes request is translated into
> REQ_OP_WRITE_ZEROES which controller is not able to process resulting in
> the error. This analysis maybe wrong.
> 
> Can you please share following details :-
> 
> nvme id-ns /dev/nvme0n1 -H (we are interested in oncs part here)

I ran the requested command against /dev/nvme1n1 (since /dev/nvme0n1 
works perfectly so far) and here is the result:

NVME Identify Namespace 1:
nsze    : 0x1dcf32b0
ncap    : 0x1dcf32b0
nuse    : 0x1dcf32b0
nsfeat  : 0
   [2:2] : 0     Deallocated or Unwritten Logical Block error Not Supported
   [1:1] : 0     Namespace uses AWUN, AWUPF, and ACWU
   [0:0] : 0     Thin Provisioning Not Supported

nlbaf   : 0
flbas   : 0
   [4:4] : 0     Metadata Transferred in Separate Contiguous Buffer
   [3:0] : 0     Current LBA Format Selected

mc      : 0
   [1:1] : 0     Metadata Pointer Not Supported
   [0:0] : 0     Metadata as Part of Extended Data LBA Not Supported

dpc     : 0
   [4:4] : 0     Protection Information Transferred as Last 8 Bytes of 
Metadata Not Supported
   [3:3] : 0     Protection Information Transferred as First 8 Bytes of 
Metadata Not Supported
   [2:2] : 0     Protection Information Type 3 Not Supported
   [1:1] : 0     Protection Information Type 2 Not Supported
   [0:0] : 0     Protection Information Type 1 Not Supported

dps     : 0
   [3:3] : 0     Protection Information is Transferred as Last 8 Bytes 
of Metadata
   [2:0] : 0     Protection Information Disabled

nmic    : 0
   [0:0] : 0     Namespace Multipath Not Capable

rescap  : 0
   [6:6] : 0     Exclusive Access - All Registrants Not Supported
   [5:5] : 0     Write Exclusive - All Registrants Not Supported
   [4:4] : 0     Exclusive Access - Registrants Only Not Supported
   [3:3] : 0     Write Exclusive - Registrants Only Not Supported
   [2:2] : 0     Exclusive Access Not Supported
   [1:1] : 0     Write Exclusive Not Supported
   [0:0] : 0     Persist Through Power Loss Not Supported

fpi     : 0x80
   [7:7] : 0x1   Format Progress Indicator Supported
   [6:0] : 0     Format Progress Indicator (Remaining 0%)

dlfeat  : 1
   [4:4] : 0     Guard Field of Deallocated Logical Blocks is set to 0xFFFF
   [3:3] : 0     Deallocate Bit in the Write Zeroes Command is Not Supported
   [2:0] : 0x1   Bytes Read From a Deallocated Logical Block and its 
Metadata are 0x00

nawun   : 0
nawupf  : 0
nacwu   : 0
nabsn   : 0
nabo    : 0
nabspf  : 0
noiob   : 0
nvmcap  : 0
nsattr  : 0
nvmsetid: 0
anagrpid: 0
endgid  : 0
nguid   : 00000000000000000000000000000000
eui64   : 0000000000000000
LBA Format  0 : Metadata Size: 0   bytes - Data Size: 512 bytes - 
Relative Performance: 0 Best (in use)

> 
> Also for above device what is the value for the queue block write-zeroes
> 
> parameter that is present in the
> /sys/block/<nvmeXnY>/queue/write_zeroes_max_bytes ?

$ cat /sys/block/nvme1n1/queue/write_zeroes_max_bytes
131584

> 
> You can also try blkdiscard -z 0 -l 1024 /dev/<nvmeXnY> to see if the
> problem is with
> write zeroes.

# blkdiscard -z -l 1024 /dev/nvme1n1
blkdiscard: /dev/nvme1n1: BLKZEROOUT ioctl failed: Device or resource busy

> 
> Also can you please also try the latest nvme tree branch nvme-5.11 ?
> 

Where do I get that code from? Is it already in the 5.11-rc tree or do I 
need to look somewhere else? I checked https://github.com/linux-nvme but 
I did not see it there.

Brad


From Damien.LeMoal at wdc.com  Mon Jan 18 19:02:35 2021
From: Damien.LeMoal at wdc.com (Damien Le Moal)
Date: Tue, 19 Jan 2021 00:02:35 +0000
Subject: [PATCH V9 4/9] nvmet: add ZBD over ZNS backend support
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-5-chaitanya.kulkarni@wdc.com>
 <20210112074805.GA24443@lst.de>
 <BL0PR04MB65145CE93F2AAF66158A3D71E7AA0@BL0PR04MB6514.namprd04.prod.outlook.com>
 <20210118182515.GC11082@lst.de>
Message-ID: <BL0PR04MB6514A9C41525B7514AE129C5E7A30@BL0PR04MB6514.namprd04.prod.outlook.com>

On 2021/01/19 3:25, Christoph Hellwig wrote:
> On Tue, Jan 12, 2021 at 07:52:27AM +0000, Damien Le Moal wrote:
>>>
>>> I do not understand the logic here, given that NVMe does not have
>>> conventional zones.
>>
>> 512e SAS & SATA SMR drives (512B logical, 4K physical) are a big thing, and for
>> these, all writes in sequential zones must be 4K aligned. So I suggested to
>> Chaitanya to simply use the physical block size as the LBA size for the target
>> to avoid weird IO errors that would not make sense in ZNS/NVMe world (e.g. 512B
>> aligned write requests failing).
> 
> But in NVMe the physical block size exposes the atomic write unit, which
> could be way too large.  ?f we want to do this cleanly we need to expose
> a minimum sequential zone write alignment value in the block layer.
> 

OK, good point. I think I can cook something like that today.

-- 
Damien Le Moal
Western Digital Research


From lengchao at huawei.com  Mon Jan 18 20:50:15 2021
From: lengchao at huawei.com (Chao Leng)
Date: Tue, 19 Jan 2021 09:50:15 +0800
Subject: [PATCH v2 4/6] nvme-rdma: avoid IO error and repeated request
 completion
In-Reply-To: <20210118174913.GA8700@lst.de>
References: <20210107033149.15701-1-lengchao@huawei.com>
 <20210107033149.15701-5-lengchao@huawei.com>
 <07e41b4f-914a-11e8-5638-e2d6408feb3f@grimberg.me>
 <7b12be41-0fcd-5a22-0e01-8cd4ac9cde5b@huawei.com>
 <a3404c7d-ccc8-0d55-d4a8-fc15107c90e6@grimberg.me>
 <695b6839-5333-c342-2189-d7aaeba797a7@huawei.com>
 <4ff22d33-12fa-1f70-3606-54821f314c45@grimberg.me>
 <0b5c8e31-8dc2-994a-1710-1b1be07549c9@huawei.com>
 <20210118174913.GA8700@lst.de>
Message-ID: <2483994e-1bc2-8d80-468e-94b898b7dc09@huawei.com>



On 2021/1/19 1:49, Christoph Hellwig wrote:
> On Mon, Jan 18, 2021 at 11:22:16AM +0800, Chao Leng wrote:
>>> Well, certainly this one-shot always return 0 and complete the command
>>> with HOST_PATH error is not a good approach IMO
>> So what's the better option? Just complete the request with host path
>> error for non-ENOMEM and EAGAIN returned by the HBA driver?
> 
> what HBA driver?
mlx4 and mlx5.
> .
> 


From minwoo.im.dev at gmail.com  Mon Jan 18 22:30:58 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Tue, 19 Jan 2021 12:30:58 +0900
Subject: [PATCH V3 3/3] nvme: retry commands based on ACRE flag
In-Reply-To: <20210118174051.GA8542@lst.de>
References: <20210114133110.20779-1-minwoo.im.dev@gmail.com>
 <20210114133110.20779-4-minwoo.im.dev@gmail.com>
 <20210115170412.GA1515933@dhcp-10-100-145-180.wdc.com>
 <20210115182602.GA2822@localhost.localdomain>
 <20210118174051.GA8542@lst.de>
Message-ID: <20210119033058.GE5939@localhost.localdomain>

On 21-01-18 18:40:51, Christoph Hellwig wrote:
> On Sat, Jan 16, 2021 at 03:26:02AM +0900, Minwoo Im wrote:
> > > I am not sure we should ignore the FAILFAST for non-path errors. If we
> > > need retryable admin commands, we should let the driver provide a way
> > > for callers to dispatch requests without that flag.
> > 
> > Understood.  I thought the opposite way about FAILFAST in case with
> > acre, if device is enabled with acre, all commands would be retried
> > regardless to FAILFAST...  Thanks for pointing that out!
> > 
> > How do you think which one is right choice to go with if a user-space
> > application(e.g., nvme-cli) wants a command to be retired in case of
> > ACRE && Error && !DNR:
> > 
> >   - User-space application should figure out !DNR and retry the command.
> >     (Maybe we are not able to easily figure out exact status code from
> >     the user-space application by the return value).
> > 
> >   - Driver should retry the command right before putting result up to
> >     the user-space even it's a FAILFAST request.
> > 
> > Thanks,
> 
> We could come up with a version of the ioctls that use the normal
> retry mechanisms.  nvme_passthru_cmd64 has two reserved fields we
> could use for UAPI flags like this.

Thank you for your feedback on this!


From minwoo.im.dev at gmail.com  Mon Jan 18 22:43:38 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Tue, 19 Jan 2021 12:43:38 +0900
Subject: [PATCH V3 1/3] nvme: check all retry delay times in Identify
 Controller
In-Reply-To: <20210114133110.20779-2-minwoo.im.dev@gmail.com>
References: <20210114133110.20779-1-minwoo.im.dev@gmail.com>
 <20210114133110.20779-2-minwoo.im.dev@gmail.com>
Message-ID: <20210119034338.GF5939@localhost.localdomain>

On 21-01-14 22:31:08, Minwoo Im wrote:
> If none of Command Retry Delay Time(CRDT)s are set, then we can simply
> skip to configure Advanced Command Retry Enable(ACRE).
> 
> CRDT selection will be made in Completion Queue Entry that controller
> has responsibility to decide.
> 
> This patch checks all CRDT[0, 1, and 2] in Identify Controller data
> structrure instead of checking the first one: CRDT[0] for cases that:
> 
> 	- CRDT[0] == 0, but CRDT[1 or 2] != 0
> 
> Signed-off-by: Minwoo Im <minwoo.im.dev at gmail.com>
> ---
>  drivers/nvme/host/core.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
> index fff49e544fdf..a8cee380b3c0 100644
> --- a/drivers/nvme/host/core.c
> +++ b/drivers/nvme/host/core.c
> @@ -2499,7 +2499,7 @@ static int nvme_configure_acre(struct nvme_ctrl *ctrl)
>  	int ret;
>  
>  	/* Don't bother enabling the feature if retry delay is not reported */
> -	if (!ctrl->crdt[0])
> +	if (!ctrl->crdt[0] && !ctrl->crdt[1] && !ctrl->crdt[2])
>  		return 0;
>  
>  	host = kzalloc(sizeof(*host), GFP_KERNEL);
> -- 
> 2.17.1
> 

Hello Christoph, and Keith,

May I get your feedback on this?  Is there any background reason not to
configure ACRE without checking CRDT2[1] and CRDT3[2] ?

Thanks!


From dsahern at gmail.com  Mon Jan 18 22:47:08 2021
From: dsahern at gmail.com (David Ahern)
Date: Mon, 18 Jan 2021 20:47:08 -0700
Subject: [PATCH v2 net-next 06/21] nvme-tcp: Add DDP offload control path
In-Reply-To: <20210114151033.13020-7-borisp@mellanox.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
 <20210114151033.13020-7-borisp@mellanox.com>
Message-ID: <37861060-9651-49c8-e583-2b070914361c@gmail.com>

On 1/14/21 8:10 AM, Boris Pismenny wrote:
> +static
> +int nvme_tcp_offload_socket(struct nvme_tcp_queue *queue)
> +{
> +	struct net_device *netdev = get_netdev_for_sock(queue->sock->sk, true);
> +	struct nvme_tcp_ddp_config config = {};
> +	int ret;
> +
> +	if (!netdev) {
> +		dev_info_ratelimited(queue->ctrl->ctrl.device, "netdev not found\n");
> +		return -ENODEV;
> +	}
> +
> +	if (!(netdev->features & NETIF_F_HW_TCP_DDP)) {
> +		dev_put(netdev);
> +		return -EOPNOTSUPP;
> +	}
> +
> +	config.cfg.type		= TCP_DDP_NVME;
> +	config.pfv		= NVME_TCP_PFV_1_0;
> +	config.cpda		= 0;
> +	config.dgst		= queue->hdr_digest ?
> +		NVME_TCP_HDR_DIGEST_ENABLE : 0;
> +	config.dgst		|= queue->data_digest ?
> +		NVME_TCP_DATA_DIGEST_ENABLE : 0;
> +	config.queue_size	= queue->queue_size;
> +	config.queue_id		= nvme_tcp_queue_id(queue);
> +	config.io_cpu		= queue->io_cpu;
> +
> +	ret = netdev->tcp_ddp_ops->tcp_ddp_sk_add(netdev,
> +						  queue->sock->sk,
> +						  (struct tcp_ddp_config *)&config);

typecast is not needed; tcp_ddp_config is an element of nvme_tcp_ddp_config

> +	if (ret) {
> +		dev_put(netdev);
> +		return ret;
> +	}
> +
> +	inet_csk(queue->sock->sk)->icsk_ulp_ddp_ops = &nvme_tcp_ddp_ulp_ops;
> +	if (netdev->features & NETIF_F_HW_TCP_DDP)
> +		set_bit(NVME_TCP_Q_OFF_DDP, &queue->flags);
> +
> +	return ret;
> +}
> +
> +static
> +void nvme_tcp_unoffload_socket(struct nvme_tcp_queue *queue)
> +{
> +	struct net_device *netdev = queue->ctrl->offloading_netdev;
> +
> +	if (!netdev) {
> +		dev_info_ratelimited(queue->ctrl->ctrl.device, "netdev not found\n");
> +		return;
> +	}
> +
> +	netdev->tcp_ddp_ops->tcp_ddp_sk_del(netdev, queue->sock->sk);
> +
> +	inet_csk(queue->sock->sk)->icsk_ulp_ddp_ops = NULL;
> +	dev_put(netdev); /* put the queue_init get_netdev_for_sock() */

have you validated the netdev reference counts? You have a put here, and ...

> +}
> +
> +static
> +int nvme_tcp_offload_limits(struct nvme_tcp_queue *queue)
> +{
> +	struct net_device *netdev = get_netdev_for_sock(queue->sock->sk, true);

... a get here ....

> +	struct tcp_ddp_limits limits;
> +	int ret = 0;
> +
> +	if (!netdev) {
> +		dev_info_ratelimited(queue->ctrl->ctrl.device, "netdev not found\n");
> +		return -ENODEV;
> +	}
> +
> +	if (netdev->features & NETIF_F_HW_TCP_DDP &&
> +	    netdev->tcp_ddp_ops &&
> +	    netdev->tcp_ddp_ops->tcp_ddp_limits)
> +		ret = netdev->tcp_ddp_ops->tcp_ddp_limits(netdev, &limits);
> +	else
> +		ret = -EOPNOTSUPP;
> +
> +	if (!ret) {
> +		queue->ctrl->offloading_netdev = netdev;


... you have the device here, but then ...

> +		dev_dbg_ratelimited(queue->ctrl->ctrl.device,
> +				    "netdev %s offload limits: max_ddp_sgl_len %d\n",
> +				    netdev->name, limits.max_ddp_sgl_len);
> +		queue->ctrl->ctrl.max_segments = limits.max_ddp_sgl_len;
> +		queue->ctrl->ctrl.max_hw_sectors =
> +			limits.max_ddp_sgl_len << (ilog2(SZ_4K) - 9);
> +	} else {
> +		queue->ctrl->offloading_netdev = NULL;
> +	}
> +
> +	dev_put(netdev);

... put here. And this is the limit checking function which seems like
an odd place to set offloading_netdev vs nvme_tcp_offload_socket which
sets no queue variable but yet hangs on to a netdev reference count.

netdev reference count leaks are an absolute PITA to find. Code that
takes and puts the counts should be clear and obvious as to when and
why. The symmetry of offload and unoffload are clear when the offload
saves the address in offloading_netdev. What you have now is dubious.



From dsahern at gmail.com  Mon Jan 18 23:18:44 2021
From: dsahern at gmail.com (David Ahern)
Date: Mon, 18 Jan 2021 21:18:44 -0700
Subject: [PATCH v2 net-next 07/21] nvme-tcp: Add DDP data-path
In-Reply-To: <20210114151033.13020-8-borisp@mellanox.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
 <20210114151033.13020-8-borisp@mellanox.com>
Message-ID: <84cc2af1-22e8-abf5-07da-bc7b4a2b6b12@gmail.com>

On 1/14/21 8:10 AM, Boris Pismenny wrote:
> @@ -664,8 +753,15 @@ static int nvme_tcp_process_nvme_cqe(struct nvme_tcp_queue *queue,
>  		return -EINVAL;
>  	}
>  
> -	if (!nvme_try_complete_req(rq, cqe->status, cqe->result))
> -		nvme_complete_rq(rq);
> +	req = blk_mq_rq_to_pdu(rq);
> +	if (req->offloaded) {
> +		req->status = cqe->status;
> +		req->result = cqe->result;
> +		nvme_tcp_teardown_ddp(queue, cqe->command_id, rq);
> +	} else {
> +		if (!nvme_try_complete_req(rq, cqe->status, cqe->result))
> +			nvme_complete_rq(rq);
> +	}
>  	queue->nr_cqe++;
>  
>  	return 0;
> @@ -859,9 +955,18 @@ static int nvme_tcp_recv_pdu(struct nvme_tcp_queue *queue, struct sk_buff *skb,
>  static inline void nvme_tcp_end_request(struct request *rq, u16 status)
>  {
>  	union nvme_result res = {};
> +	struct nvme_tcp_request *req = blk_mq_rq_to_pdu(rq);
> +	struct nvme_tcp_queue *queue = req->queue;
> +	struct nvme_tcp_data_pdu *pdu = (void *)queue->pdu;
>  
> -	if (!nvme_try_complete_req(rq, cpu_to_le16(status << 1), res))
> -		nvme_complete_rq(rq);
> +	if (req->offloaded) {
> +		req->status = cpu_to_le16(status << 1);
> +		req->result = res;
> +		nvme_tcp_teardown_ddp(queue, pdu->command_id, rq);
> +	} else {
> +		if (!nvme_try_complete_req(rq, cpu_to_le16(status << 1), res))
> +			nvme_complete_rq(rq);
> +	}
>  }
>  
>  static int nvme_tcp_recv_data(struct nvme_tcp_queue *queue, struct sk_buff *skb,


The req->offload checks assume the offload is to the expected
offload_netdev, but you do not verify the data arrived as expected. You
might get lucky if both netdev's belong to the same PCI device (assuming
the h/w handles it a certain way), but it will not if the netdev's
belong to different devices.

Consider a system with 2 network cards -- even if it is 2 mlx5 based
devices. One setup can have the system using a bond with 1 port from
each PCI device. The tx path picks a leg based on the hash of the ntuple
and that (with Tariq's bond patches) becomes the expected offload
device. A similar example holds for a pure routing setup with ECMP. For
both there is full redundancy in the network - separate NIC cards
connected to separate TORs to have independent network paths.

A packet arrives on the *other* netdevice - you have *no* control over
the Rx path. Your current checks will think the packet arrived with DDP
but it did not.


From Damien.LeMoal at wdc.com  Mon Jan 18 23:28:00 2021
From: Damien.LeMoal at wdc.com (Damien Le Moal)
Date: Tue, 19 Jan 2021 04:28:00 +0000
Subject: [PATCH V9 4/9] nvmet: add ZBD over ZNS backend support
In-Reply-To: <20210118182515.GC11082@lst.de>
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-5-chaitanya.kulkarni@wdc.com>
 <20210112074805.GA24443@lst.de>
 <BL0PR04MB65145CE93F2AAF66158A3D71E7AA0@BL0PR04MB6514.namprd04.prod.outlook.com>
 <20210118182515.GC11082@lst.de>
Message-ID: <2c3a1a515bd3913f46ecf81a157e35ff56a1fb70.camel@wdc.com>

On Mon, 2021-01-18 at 19:25 +0100, Christoph Hellwig wrote:
> On Tue, Jan 12, 2021 at 07:52:27AM +0000, Damien Le Moal wrote:
> > > 
> > > I do not understand the logic here, given that NVMe does not have
> > > conventional zones.
> > 
> > 512e SAS & SATA SMR drives (512B logical, 4K physical) are a big thing, and for
> > these, all writes in sequential zones must be 4K aligned. So I suggested to
> > Chaitanya to simply use the physical block size as the LBA size for the target
> > to avoid weird IO errors that would not make sense in ZNS/NVMe world (e.g. 512B
> > aligned write requests failing).
> 
> But in NVMe the physical block size exposes the atomic write unit, which
> could be way too large.  ?f we want to do this cleanly we need to expose
> a minimum sequential zone write alignment value in the block layer.

What about something like this below to add to Chaitanya series ?
This adds the queue limit zone_write_granularity which is set to the physical
block size for scsi, and for NVMe/ZNS too since that value is limited to the
atomic block size. Lightly tested with both 512e and 4kn SMR drives.


diff --git a/block/blk-settings.c b/block/blk-settings.c
index 43990b1d148b..d6c2677a38df 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -60,6 +60,7 @@ void blk_set_default_limits(struct queue_limits *lim)
 	lim->io_opt = 0;
 	lim->misaligned = 0;
 	lim->zoned = BLK_ZONED_NONE;
+	lim->zone_write_granularity = 0;
 }
 EXPORT_SYMBOL(blk_set_default_limits);
 
@@ -341,6 +342,14 @@ void blk_queue_logical_block_size(struct request_queue *q,
unsigned int size)
 		round_down(limits->max_hw_sectors, size >> SECTOR_SHIFT);
 	limits->max_sectors =
 		round_down(limits->max_sectors, size >> SECTOR_SHIFT);
+
+	if (blk_queue_is_zoned(q)) {
+		if (limits->zone_write_granularity < limits-
>logical_block_size)
+			limits->zone_write_granularity =
+				limits->logical_block_size;
+		if (q->limits.zone_write_granularity < q->limits.io_min)
+			q->limits.zone_write_granularity = q->limits.io_min;
+	}
 }
 EXPORT_SYMBOL(blk_queue_logical_block_size);
 
@@ -361,11 +370,39 @@ void blk_queue_physical_block_size(struct request_queue
*q, unsigned int size)
 	if (q->limits.physical_block_size < q->limits.logical_block_size)
 		q->limits.physical_block_size = q->limits.logical_block_size;
 
-	if (q->limits.io_min < q->limits.physical_block_size)
+	if (q->limits.io_min < q->limits.physical_block_size) {
 		q->limits.io_min = q->limits.physical_block_size;
+		if (blk_queue_is_zoned(q)
+		    && q->limits.zone_write_granularity < q->limits.io_min)
+			q->limits.zone_write_granularity = q->limits.io_min;
+	}
 }
 EXPORT_SYMBOL(blk_queue_physical_block_size);
 
+/**
+ * blk_queue_zone_write_granularity - set zone write granularity for the queue
+ * @q:  the request queue for the zoned device
+ * @size:  the zone write granularity size, in bytes
+ *
+ * Description:
+ *   This should be set to the lowest possible size allowing to write in
+ *   sequential zones of a zoned block device.
+ */
+void blk_queue_zone_write_granularity(struct request_queue *q, unsigned int
size)
+{
+	if (WARN_ON(!blk_queue_is_zoned(q)))
+		return;
+
+	q->limits.zone_write_granularity = size;
+
+	if (q->limits.zone_write_granularity < q->limits.logical_block_size)
+		q->limits.zone_write_granularity = q-
>limits.logical_block_size;
+
+	if (q->limits.zone_write_granularity < q->limits.io_min)
+		q->limits.zone_write_granularity = q->limits.io_min;
+}
+EXPORT_SYMBOL(blk_queue_zone_write_granularity);
+
 /**
  * blk_queue_alignment_offset - set physical block alignment offset
  * @q:	the request queue for the device
@@ -631,6 +668,8 @@ int blk_stack_limits(struct queue_limits *t, struct
queue_limits *b,
 			t->discard_granularity;
 	}
 
+	t->zone_write_granularity = max(t->zone_write_granularity,
+					b->zone_write_granularity);
 	t->zoned = max(t->zoned, b->zoned);
 	return ret;
 }
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index b513f1683af0..7ea3dd4d876b 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -219,6 +219,11 @@ static ssize_t queue_write_zeroes_max_show(struct
request_queue *q, char *page)
 		(unsigned long long)q->limits.max_write_zeroes_sectors << 9);
 }
 
+static ssize_t queue_zone_write_granularity_show(struct request_queue *q, char
*page)
+{
+	return queue_var_show(q->limits.zone_write_granularity, page);
+}
+
 static ssize_t queue_zone_append_max_show(struct request_queue *q, char *page)
 {
 	unsigned long long max_sectors = q->limits.max_zone_append_sectors;
@@ -585,6 +590,7 @@ QUEUE_RO_ENTRY(queue_discard_zeroes_data,
"discard_zeroes_data");
 QUEUE_RO_ENTRY(queue_write_same_max, "write_same_max_bytes");
 QUEUE_RO_ENTRY(queue_write_zeroes_max, "write_zeroes_max_bytes");
 QUEUE_RO_ENTRY(queue_zone_append_max, "zone_append_max_bytes");
+QUEUE_RO_ENTRY(queue_zone_write_granularity, "zone_write_granularity");
 
 QUEUE_RO_ENTRY(queue_zoned, "zoned");
 QUEUE_RO_ENTRY(queue_nr_zones, "nr_zones");
@@ -639,6 +645,7 @@ static struct attribute *queue_attrs[] = {
 	&queue_write_same_max_entry.attr,
 	&queue_write_zeroes_max_entry.attr,
 	&queue_zone_append_max_entry.attr,
+	&queue_zone_write_granularity_entry.attr,
 	&queue_nonrot_entry.attr,
 	&queue_zoned_entry.attr,
 	&queue_nr_zones_entry.attr,
diff --git a/drivers/nvme/host/zns.c b/drivers/nvme/host/zns.c
index 1dfe9a3500e3..def76ac88248 100644
--- a/drivers/nvme/host/zns.c
+++ b/drivers/nvme/host/zns.c
@@ -113,6 +113,13 @@ int nvme_update_zone_info(struct nvme_ns *ns, unsigned
lbaf)
 	blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, q);
 	blk_queue_max_open_zones(q, le32_to_cpu(id->mor) + 1);
 	blk_queue_max_active_zones(q, le32_to_cpu(id->mar) + 1);
+
+	/*
+	 * The physical block size is limited to the Atomic Write Unit Power
+	 * Fail parameter. Use this value as the zone write granularity as it
+	 * may be different from the logical block size.
+	 */
+	blk_queue_zone_write_granularity(q, q->limits.physical_block_size);
 free_data:
 	kfree(id);
 	return status;
diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c
index cf07b7f93579..41d602f7e62e 100644
--- a/drivers/scsi/sd_zbc.c
+++ b/drivers/scsi/sd_zbc.c
@@ -789,6 +789,16 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned
char *buf)
 	blk_queue_max_active_zones(q, 0);
 	nr_zones = round_up(sdkp->capacity, zone_blocks) >>
ilog2(zone_blocks);
 
+	/*
+	 * Per ZBC and ZAC specifications, writes in sequential write required
+	 * zones of host-managed devices must be aligned to the device
physical
+	 * block size.
+	 */
+	if (blk_queue_zoned_model(q) == BLK_ZONED_HM)
+		blk_queue_zone_write_granularity(q, sdkp-
>physical_block_size);
+	else
+		blk_queue_zone_write_granularity(q, sdkp->device-
>sector_size);
+
 	/* READ16/WRITE16 is mandatory for ZBC disks */
 	sdkp->device->use_16_for_rw = 1;
 	sdkp->device->use_10_for_rw = 0;
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index f94ee3089e01..4b4df2644882 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -337,6 +337,7 @@ struct queue_limits {
 	unsigned int		max_zone_append_sectors;
 	unsigned int		discard_granularity;
 	unsigned int		discard_alignment;
+	unsigned int		zone_write_granularity;
 
 	unsigned short		max_segments;
 	unsigned short		max_integrity_segments;
@@ -1161,6 +1162,7 @@ extern void blk_queue_logical_block_size(struct
request_queue *, unsigned int);
 extern void blk_queue_max_zone_append_sectors(struct request_queue *q,
 		unsigned int max_zone_append_sectors);
 extern void blk_queue_physical_block_size(struct request_queue *, unsigned
int);
+void blk_queue_zone_write_granularity(struct request_queue *, unsigned int);
 extern void blk_queue_alignment_offset(struct request_queue *q,
 				       unsigned int alignment);
 void blk_queue_update_readahead(struct request_queue *q);



-- 
Damien Le Moal
Western Digital

From dsahern at gmail.com  Mon Jan 18 23:36:30 2021
From: dsahern at gmail.com (David Ahern)
Date: Mon, 18 Jan 2021 21:36:30 -0700
Subject: [PATCH v2 net-next 19/21] net/mlx5e: NVMEoTCP, data-path for DDP
 offload
In-Reply-To: <15248743-82bf-4283-d8c6-99f2210e42ae@gmail.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
 <20210114151033.13020-20-borisp@mellanox.com>
 <10c28b01-49e5-c512-8670-bf8332b24b1b@gmail.com>
 <15248743-82bf-4283-d8c6-99f2210e42ae@gmail.com>
Message-ID: <2a0bfce0-6226-7b9a-95b1-15f4f1f321e8@gmail.com>

On 1/17/21 1:42 AM, Boris Pismenny wrote:
> This is needed for a few reasons that are explained in detail
> in the tcp-ddp offload documentation. See patch 21 overview
> and rx-data-path sections. Our reasons are as follows:

I read the documentation patch, and it does not explain it and really
should not since this is very mlx specific based on the changes.
Different h/w will have different limitations. Given that, it would be
best to enhance the patch description to explain why these gymnastics
are needed for the skb.

> 1) Each SKB may contain multiple PDUs. DDP offload doesn't operate on
> PDU headers, so these are written in the receive ring. Therefore, we
> need to rebuild the SKB to account for it. Additionally, due to HW
> limitations, we will only offload the first PDU in the SKB.

Are you referring to LRO skbs here? I can't imagine going through this
for 1500 byte packets that have multiple PDUs.


> 2) The newly constructed SKB represents the original data as it is on
> the wire, such that the network stack is oblivious to the offload.
> 3) We decided not to modify all of the mlx5e_skb_from_cqe* functions
> because it would make the offload harder to distinguish, and it would
> add overhead to the existing data-path fucntions. Therefore, we opted
> for this modular approach.
> 
> If we only had generic header-data split, then we just couldn't
> provide this offload. It is not enough to place payload into some
> buffer without TCP headers because RPC protocols and advanced storage
> protocols, such as nvme-tcp, reorder their responses and require data
> to be placed into application/pagecache buffers, which are anything
> but anonymous. In other words, header-data split alone writes data
> to the wrong buffers (reordering), or to anonymous buffers that
> can't be page-flipped to replace application/pagecache buffers.
> 



From Chaitanya.Kulkarni at wdc.com  Mon Jan 18 23:57:03 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Tue, 19 Jan 2021 04:57:03 +0000
Subject: [PATCH V9 5/9] nvmet: add bio get helper for different backends
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-6-chaitanya.kulkarni@wdc.com>
 <20210112073315.GA24288@lst.de>
 <BYAPR04MB4965361DC74566BD26E3DC7B86A90@BYAPR04MB4965.namprd04.prod.outlook.com>
 <20210118182803.GE11082@lst.de>
Message-ID: <BYAPR04MB4965673DF0282A743CA37CB786A30@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/18/21 10:28 AM, Christoph Hellwig wrote:
> On Wed, Jan 13, 2021 at 05:03:05AM +0000, Chaitanya Kulkarni wrote:
>> On 1/11/21 23:33, Christoph Hellwig wrote:
>>> I'm not a huge fan of this helper, especially as it sets an end_io
>>> callback only for the allocated case, which is a weird calling
>>> convention.
>>>
>> The patch has a right documentation and that end_io is needed
>> for passthru case. To get rid of the weirdness I can remove
>> passthru case and make itend_io assign to inline and non-inline bio
>> to make it non-weired.
>>
>> Since this eliminates exactly identical lines of the code in atleast two
>> backend which we should try to use the helper in non-wried way.
> I really do not like helper that just eliminate "duplicate lines" vs
> encapsulating logic that makes sense one its own.
>
Okay, I'll drop it, next version.



From lkp at intel.com  Tue Jan 19 01:09:49 2021
From: lkp at intel.com (kernel test robot)
Date: Tue, 19 Jan 2021 14:09:49 +0800
Subject: [linux-nvme:nvme-5.11] BUILD SUCCESS
 bffcd507780ea614b5543c66f2e37ce0d55cd449
Message-ID: <600677ad.FOQOU+qZcfQ3BgvI%lkp@intel.com>

tree/branch: git://git.infradead.org/nvme.git nvme-5.11
branch HEAD: bffcd507780ea614b5543c66f2e37ce0d55cd449  nvmet: set right status on error in id-ns handler

elapsed time: 724m

configs tested: 132
configs skipped: 2

The following configs have been built successfully.
More configs may be tested in the coming days.

gcc tested configs:
arm                                 defconfig
arm64                            allyesconfig
arm64                               defconfig
arm                              allyesconfig
arm                              allmodconfig
sh                 kfr2r09-romimage_defconfig
sparc                            allyesconfig
sparc64                             defconfig
arm                          pxa910_defconfig
powerpc                         ps3_defconfig
arm                     am200epdkit_defconfig
mips                      loongson3_defconfig
ia64                             alldefconfig
powerpc                      tqm8xx_defconfig
sh                          polaris_defconfig
m68k                        mvme147_defconfig
arm                          tango4_defconfig
powerpc                  iss476-smp_defconfig
s390                       zfcpdump_defconfig
powerpc                      ep88xc_defconfig
powerpc                      mgcoge_defconfig
arm                            xcep_defconfig
powerpc                 mpc837x_rdb_defconfig
arm                         nhk8815_defconfig
h8300                     edosk2674_defconfig
mips                     decstation_defconfig
mips                malta_qemu_32r6_defconfig
arm                         s3c2410_defconfig
sh                              ul2_defconfig
m68k                          multi_defconfig
powerpc                      pcm030_defconfig
sh                   sh7724_generic_defconfig
xtensa                    smp_lx200_defconfig
arm                             ezx_defconfig
arm                           viper_defconfig
arm                            zeus_defconfig
mips                      bmips_stb_defconfig
arm                            hisi_defconfig
arm                         vf610m4_defconfig
arm                        shmobile_defconfig
arm                       netwinder_defconfig
parisc                generic-32bit_defconfig
powerpc                      katmai_defconfig
powerpc                     tqm8548_defconfig
mips                          rm200_defconfig
arm                        magician_defconfig
h8300                               defconfig
openrisc                 simple_smp_defconfig
powerpc                 mpc85xx_cds_defconfig
powerpc                 xes_mpc85xx_defconfig
arm                      tct_hammer_defconfig
mips                           jazz_defconfig
powerpc                     skiroot_defconfig
xtensa                generic_kc705_defconfig
powerpc                     tqm5200_defconfig
m68k                         amcore_defconfig
xtensa                       common_defconfig
sh                            hp6xx_defconfig
i386                             alldefconfig
m68k                            q40_defconfig
powerpc                 mpc8560_ads_defconfig
csky                                defconfig
mips                    maltaup_xpa_defconfig
ia64                             allmodconfig
ia64                                defconfig
ia64                             allyesconfig
m68k                             allmodconfig
m68k                                defconfig
m68k                             allyesconfig
nios2                               defconfig
arc                              allyesconfig
nds32                             allnoconfig
c6x                              allyesconfig
nds32                               defconfig
nios2                            allyesconfig
alpha                               defconfig
alpha                            allyesconfig
xtensa                           allyesconfig
h8300                            allyesconfig
arc                                 defconfig
sh                               allmodconfig
parisc                              defconfig
s390                             allyesconfig
parisc                           allyesconfig
s390                                defconfig
sparc                               defconfig
i386                               tinyconfig
i386                             allyesconfig
i386                                defconfig
mips                             allyesconfig
mips                             allmodconfig
powerpc                          allyesconfig
powerpc                          allmodconfig
powerpc                           allnoconfig
i386                 randconfig-a002-20210118
i386                 randconfig-a005-20210118
i386                 randconfig-a006-20210118
i386                 randconfig-a001-20210118
i386                 randconfig-a003-20210118
i386                 randconfig-a004-20210118
x86_64               randconfig-a015-20210118
x86_64               randconfig-a013-20210118
x86_64               randconfig-a012-20210118
x86_64               randconfig-a016-20210118
x86_64               randconfig-a011-20210118
x86_64               randconfig-a014-20210118
i386                 randconfig-a011-20210118
i386                 randconfig-a012-20210118
i386                 randconfig-a016-20210118
i386                 randconfig-a015-20210118
i386                 randconfig-a013-20210118
i386                 randconfig-a014-20210118
riscv                    nommu_k210_defconfig
riscv                            allyesconfig
riscv                    nommu_virt_defconfig
riscv                             allnoconfig
riscv                               defconfig
riscv                          rv32_defconfig
riscv                            allmodconfig
x86_64                                   rhel
x86_64                           allyesconfig
x86_64                    rhel-7.6-kselftests
x86_64                              defconfig
x86_64                               rhel-8.3
x86_64                      rhel-8.3-kbuiltin
x86_64                                  kexec

clang tested configs:
x86_64               randconfig-a004-20210118
x86_64               randconfig-a006-20210118
x86_64               randconfig-a001-20210118
x86_64               randconfig-a003-20210118
x86_64               randconfig-a005-20210118
x86_64               randconfig-a002-20210118

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all at lists.01.org


From hch at lst.de  Tue Jan 19 01:15:36 2021
From: hch at lst.de (hch at lst.de)
Date: Tue, 19 Jan 2021 07:15:36 +0100
Subject: [PATCH V9 4/9] nvmet: add ZBD over ZNS backend support
In-Reply-To: <2c3a1a515bd3913f46ecf81a157e35ff56a1fb70.camel@wdc.com>
References: <20210112042623.6316-1-chaitanya.kulkarni@wdc.com>
 <20210112042623.6316-5-chaitanya.kulkarni@wdc.com>
 <20210112074805.GA24443@lst.de>
 <BL0PR04MB65145CE93F2AAF66158A3D71E7AA0@BL0PR04MB6514.namprd04.prod.outlook.com>
 <20210118182515.GC11082@lst.de>
 <2c3a1a515bd3913f46ecf81a157e35ff56a1fb70.camel@wdc.com>
Message-ID: <20210119061536.GB21250@lst.de>

On Tue, Jan 19, 2021 at 04:28:00AM +0000, Damien Le Moal wrote:
> What about something like this below to add to Chaitanya series ?
> This adds the queue limit zone_write_granularity which is set to the physical
> block size for scsi, and for NVMe/ZNS too since that value is limited to the
> atomic block size. Lightly tested with both 512e and 4kn SMR drives.

For ZNS it should just be the logic block size, the atomic size is not
the right thing use here.

> +	if (blk_queue_is_zoned(q)) {
> +		if (limits->zone_write_granularity < limits-
> >logical_block_size)

Overly long line here, and your mailer wrapped it as a punishment :)

That being said I don't think the normal path to set the block size
should affect it.  Just add the manual call and leave the non-zoned
path alone.

> +EXPORT_SYMBOL(blk_queue_zone_write_granularity);

EXPORT_SYMBOL_GPL for all zoned stuff.


From hare at suse.de  Tue Jan 19 01:22:42 2021
From: hare at suse.de (Hannes Reinecke)
Date: Tue, 19 Jan 2021 07:22:42 +0100
Subject: [PATCH] nvme/hwmon: rework to avoid devm allocation
Message-ID: <20210119062242.123824-1-hare@suse.de>

The original design to use device-managed resource allocation
doesn't really work as the NVMe controller has a vastly different
lifetime than the hwmon sysfs attributes, causing warning about
duplicate sysfs entries upon reconnection.
This patch reworks the hwmon allocation to avoid device-managed
resource allocation, and uses the NVMe controller as parent for
the sysfs attributes.

Signed-off-by: Hannes Reinecke <hare at suse.de>
Tested-by: Daniel Wagner <dwagner at suse.de>
---
 drivers/nvme/host/core.c  |  1 +
 drivers/nvme/host/hwmon.c | 31 +++++++++++++++++++++----------
 drivers/nvme/host/nvme.h  |  6 ++++++
 3 files changed, 28 insertions(+), 10 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index fff49e544fdf..3c6c77e44bf7 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -4419,6 +4419,7 @@ EXPORT_SYMBOL_GPL(nvme_start_ctrl);
 
 void nvme_uninit_ctrl(struct nvme_ctrl *ctrl)
 {
+	nvme_hwmon_exit(ctrl);
 	nvme_fault_inject_fini(&ctrl->fault_inject);
 	dev_pm_qos_hide_latency_tolerance(ctrl->device);
 	cdev_device_del(&ctrl->cdev, ctrl->device);
diff --git a/drivers/nvme/host/hwmon.c b/drivers/nvme/host/hwmon.c
index 552dbc04567b..8f9e96986780 100644
--- a/drivers/nvme/host/hwmon.c
+++ b/drivers/nvme/host/hwmon.c
@@ -223,12 +223,12 @@ static const struct hwmon_chip_info nvme_hwmon_chip_info = {
 
 int nvme_hwmon_init(struct nvme_ctrl *ctrl)
 {
-	struct device *dev = ctrl->dev;
+	struct device *dev = ctrl->device;
 	struct nvme_hwmon_data *data;
 	struct device *hwmon;
 	int err;
 
-	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
 	if (!data)
 		return 0;
 
@@ -237,19 +237,30 @@ int nvme_hwmon_init(struct nvme_ctrl *ctrl)
 
 	err = nvme_hwmon_get_smart_log(data);
 	if (err) {
-		dev_warn(ctrl->device,
-			"Failed to read smart log (error %d)\n", err);
-		devm_kfree(dev, data);
+		dev_warn(dev, "Failed to read smart log (error %d)\n", err);
+		kfree(data);
 		return err;
 	}
 
-	hwmon = devm_hwmon_device_register_with_info(dev, "nvme", data,
-						     &nvme_hwmon_chip_info,
-						     NULL);
+	hwmon = hwmon_device_register_with_info(dev, "nvme",
+						data, &nvme_hwmon_chip_info,
+						NULL);
 	if (IS_ERR(hwmon)) {
 		dev_warn(dev, "Failed to instantiate hwmon device\n");
-		devm_kfree(dev, data);
+		kfree(data);
 	}
-
+	ctrl->hwmon_device = hwmon;
 	return 0;
 }
+
+void nvme_hwmon_exit(struct nvme_ctrl *ctrl)
+{
+	if (ctrl->hwmon_device) {
+		struct nvme_hwmon_data *data =
+			dev_get_drvdata(ctrl->hwmon_device);
+
+		hwmon_device_unregister(ctrl->hwmon_device);
+		ctrl->hwmon_device = NULL;
+		kfree(data);
+	}
+}
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 88a6b97247f5..f51b942bb4f5 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -246,6 +246,9 @@ struct nvme_ctrl {
 	struct rw_semaphore namespaces_rwsem;
 	struct device ctrl_device;
 	struct device *device;	/* char device */
+#ifdef CONFIG_NVME_HWMON
+	struct device *hwmon_device;
+#endif
 	struct cdev cdev;
 	struct work_struct reset_work;
 	struct work_struct delete_work;
@@ -809,11 +812,14 @@ static inline struct nvme_ns *nvme_get_ns_from_dev(struct device *dev)
 
 #ifdef CONFIG_NVME_HWMON
 int nvme_hwmon_init(struct nvme_ctrl *ctrl);
+void nvme_hwmon_exit(struct nvme_ctrl *ctrl);
 #else
 static inline int nvme_hwmon_init(struct nvme_ctrl *ctrl)
 {
 	return 0;
 }
+
+static inline int nvme_hwmon_exit(struct nvme_ctrl *ctrl) {}
 #endif
 
 u32 nvme_command_effects(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
-- 
2.29.2



From hch at lst.de  Tue Jan 19 01:28:41 2021
From: hch at lst.de (Christoph Hellwig)
Date: Tue, 19 Jan 2021 07:28:41 +0100
Subject: [PATCH] nvme/hwmon: rework to avoid devm allocation
In-Reply-To: <20210119062242.123824-1-hare@suse.de>
References: <20210119062242.123824-1-hare@suse.de>
Message-ID: <20210119062841.GB21413@lst.de>

As requested last time: please include the author of the code in the
discussion.

On Tue, Jan 19, 2021 at 07:22:42AM +0100, Hannes Reinecke wrote:
> The original design to use device-managed resource allocation
> doesn't really work as the NVMe controller has a vastly different
> lifetime than the hwmon sysfs attributes, causing warning about
> duplicate sysfs entries upon reconnection.
> This patch reworks the hwmon allocation to avoid device-managed
> resource allocation, and uses the NVMe controller as parent for
> the sysfs attributes.
> 
> Signed-off-by: Hannes Reinecke <hare at suse.de>
> Tested-by: Daniel Wagner <dwagner at suse.de>
> ---
>  drivers/nvme/host/core.c  |  1 +
>  drivers/nvme/host/hwmon.c | 31 +++++++++++++++++++++----------
>  drivers/nvme/host/nvme.h  |  6 ++++++
>  3 files changed, 28 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
> index fff49e544fdf..3c6c77e44bf7 100644
> --- a/drivers/nvme/host/core.c
> +++ b/drivers/nvme/host/core.c
> @@ -4419,6 +4419,7 @@ EXPORT_SYMBOL_GPL(nvme_start_ctrl);
>  
>  void nvme_uninit_ctrl(struct nvme_ctrl *ctrl)
>  {
> +	nvme_hwmon_exit(ctrl);
>  	nvme_fault_inject_fini(&ctrl->fault_inject);
>  	dev_pm_qos_hide_latency_tolerance(ctrl->device);
>  	cdev_device_del(&ctrl->cdev, ctrl->device);
> diff --git a/drivers/nvme/host/hwmon.c b/drivers/nvme/host/hwmon.c
> index 552dbc04567b..8f9e96986780 100644
> --- a/drivers/nvme/host/hwmon.c
> +++ b/drivers/nvme/host/hwmon.c
> @@ -223,12 +223,12 @@ static const struct hwmon_chip_info nvme_hwmon_chip_info = {
>  
>  int nvme_hwmon_init(struct nvme_ctrl *ctrl)
>  {
> -	struct device *dev = ctrl->dev;
> +	struct device *dev = ctrl->device;
>  	struct nvme_hwmon_data *data;
>  	struct device *hwmon;
>  	int err;
>  
> -	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
> +	data = kzalloc(sizeof(*data), GFP_KERNEL);
>  	if (!data)
>  		return 0;
>  
> @@ -237,19 +237,30 @@ int nvme_hwmon_init(struct nvme_ctrl *ctrl)
>  
>  	err = nvme_hwmon_get_smart_log(data);
>  	if (err) {
> -		dev_warn(ctrl->device,
> -			"Failed to read smart log (error %d)\n", err);
> -		devm_kfree(dev, data);
> +		dev_warn(dev, "Failed to read smart log (error %d)\n", err);
> +		kfree(data);
>  		return err;
>  	}
>  
> -	hwmon = devm_hwmon_device_register_with_info(dev, "nvme", data,
> -						     &nvme_hwmon_chip_info,
> -						     NULL);
> +	hwmon = hwmon_device_register_with_info(dev, "nvme",
> +						data, &nvme_hwmon_chip_info,
> +						NULL);
>  	if (IS_ERR(hwmon)) {
>  		dev_warn(dev, "Failed to instantiate hwmon device\n");
> -		devm_kfree(dev, data);
> +		kfree(data);
>  	}
> -
> +	ctrl->hwmon_device = hwmon;
>  	return 0;
>  }
> +
> +void nvme_hwmon_exit(struct nvme_ctrl *ctrl)
> +{
> +	if (ctrl->hwmon_device) {
> +		struct nvme_hwmon_data *data =
> +			dev_get_drvdata(ctrl->hwmon_device);
> +
> +		hwmon_device_unregister(ctrl->hwmon_device);
> +		ctrl->hwmon_device = NULL;
> +		kfree(data);
> +	}
> +}
> diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
> index 88a6b97247f5..f51b942bb4f5 100644
> --- a/drivers/nvme/host/nvme.h
> +++ b/drivers/nvme/host/nvme.h
> @@ -246,6 +246,9 @@ struct nvme_ctrl {
>  	struct rw_semaphore namespaces_rwsem;
>  	struct device ctrl_device;
>  	struct device *device;	/* char device */
> +#ifdef CONFIG_NVME_HWMON
> +	struct device *hwmon_device;
> +#endif
>  	struct cdev cdev;
>  	struct work_struct reset_work;
>  	struct work_struct delete_work;
> @@ -809,11 +812,14 @@ static inline struct nvme_ns *nvme_get_ns_from_dev(struct device *dev)
>  
>  #ifdef CONFIG_NVME_HWMON
>  int nvme_hwmon_init(struct nvme_ctrl *ctrl);
> +void nvme_hwmon_exit(struct nvme_ctrl *ctrl);
>  #else
>  static inline int nvme_hwmon_init(struct nvme_ctrl *ctrl)
>  {
>  	return 0;
>  }
> +
> +static inline int nvme_hwmon_exit(struct nvme_ctrl *ctrl) {}
>  #endif
>  
>  u32 nvme_command_effects(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
> -- 
> 2.29.2
---end quoted text---


From lkp at intel.com  Tue Jan 19 01:42:23 2021
From: lkp at intel.com (kernel test robot)
Date: Tue, 19 Jan 2021 14:42:23 +0800
Subject: [linux-nvme:nvme-5.12] BUILD SUCCESS
 b116d37fc0f5039a084a0bebb4a48000ae2cde54
Message-ID: <60067f4f.MGXSlGOmZDV4YVzS%lkp@intel.com>

tree/branch: git://git.infradead.org/nvme.git nvme-5.12
branch HEAD: b116d37fc0f5039a084a0bebb4a48000ae2cde54  nvmet: add lba to sect conversion helpers

elapsed time: 722m

configs tested: 121
configs skipped: 2

The following configs have been built successfully.
More configs may be tested in the coming days.

gcc tested configs:
arm                                 defconfig
arm64                            allyesconfig
arm64                               defconfig
arm                              allyesconfig
arm                              allmodconfig
sh                 kfr2r09-romimage_defconfig
sparc                            allyesconfig
sparc64                             defconfig
arm                          pxa910_defconfig
powerpc                         ps3_defconfig
arm                     am200epdkit_defconfig
mips                      loongson3_defconfig
ia64                             alldefconfig
powerpc                      tqm8xx_defconfig
sh                          polaris_defconfig
m68k                        mvme147_defconfig
arm                          tango4_defconfig
powerpc                  iss476-smp_defconfig
s390                       zfcpdump_defconfig
powerpc                      ep88xc_defconfig
powerpc                      mgcoge_defconfig
arm                            xcep_defconfig
powerpc                 mpc837x_rdb_defconfig
arm                         nhk8815_defconfig
openrisc                         alldefconfig
mips                           xway_defconfig
sparc                       sparc32_defconfig
mips                       lemote2f_defconfig
arm                          imote2_defconfig
powerpc                      pcm030_defconfig
sh                   sh7724_generic_defconfig
xtensa                    smp_lx200_defconfig
arm                             ezx_defconfig
arm                           viper_defconfig
arm                            zeus_defconfig
mips                      bmips_stb_defconfig
arm                            hisi_defconfig
arm                         vf610m4_defconfig
powerpc                 xes_mpc85xx_defconfig
arm                      tct_hammer_defconfig
mips                           jazz_defconfig
powerpc                     skiroot_defconfig
xtensa                generic_kc705_defconfig
powerpc                     tqm5200_defconfig
m68k                         amcore_defconfig
xtensa                       common_defconfig
sh                            hp6xx_defconfig
i386                             alldefconfig
m68k                            q40_defconfig
powerpc                 mpc8560_ads_defconfig
mips                    maltaup_xpa_defconfig
ia64                             allmodconfig
ia64                                defconfig
ia64                             allyesconfig
m68k                             allmodconfig
m68k                                defconfig
m68k                             allyesconfig
nios2                               defconfig
arc                              allyesconfig
nds32                             allnoconfig
c6x                              allyesconfig
nds32                               defconfig
nios2                            allyesconfig
csky                                defconfig
alpha                               defconfig
alpha                            allyesconfig
xtensa                           allyesconfig
h8300                            allyesconfig
arc                                 defconfig
sh                               allmodconfig
parisc                              defconfig
s390                             allyesconfig
parisc                           allyesconfig
s390                                defconfig
i386                             allyesconfig
sparc                               defconfig
i386                               tinyconfig
i386                                defconfig
mips                             allyesconfig
mips                             allmodconfig
powerpc                          allyesconfig
powerpc                          allmodconfig
powerpc                           allnoconfig
i386                 randconfig-a002-20210118
i386                 randconfig-a005-20210118
i386                 randconfig-a006-20210118
i386                 randconfig-a001-20210118
i386                 randconfig-a003-20210118
i386                 randconfig-a004-20210118
x86_64               randconfig-a015-20210118
x86_64               randconfig-a013-20210118
x86_64               randconfig-a012-20210118
x86_64               randconfig-a016-20210118
x86_64               randconfig-a011-20210118
x86_64               randconfig-a014-20210118
i386                 randconfig-a011-20210118
i386                 randconfig-a012-20210118
i386                 randconfig-a016-20210118
i386                 randconfig-a015-20210118
i386                 randconfig-a013-20210118
i386                 randconfig-a014-20210118
riscv                    nommu_k210_defconfig
riscv                            allyesconfig
riscv                    nommu_virt_defconfig
riscv                             allnoconfig
riscv                               defconfig
riscv                          rv32_defconfig
riscv                            allmodconfig
x86_64                                   rhel
x86_64                           allyesconfig
x86_64                    rhel-7.6-kselftests
x86_64                              defconfig
x86_64                               rhel-8.3
x86_64                      rhel-8.3-kbuiltin
x86_64                                  kexec

clang tested configs:
x86_64               randconfig-a004-20210118
x86_64               randconfig-a006-20210118
x86_64               randconfig-a001-20210118
x86_64               randconfig-a003-20210118
x86_64               randconfig-a005-20210118
x86_64               randconfig-a002-20210118

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all at lists.01.org


From hare at suse.de  Tue Jan 19 01:43:18 2021
From: hare at suse.de (Hannes Reinecke)
Date: Tue, 19 Jan 2021 07:43:18 +0100
Subject: [PATCHv2] nvme/hwmon: rework to avoid devm allocation
Message-ID: <20210119064318.124415-1-hare@suse.de>

The original design to use device-managed resource allocation
doesn't really work as the NVMe controller has a vastly different
lifetime than the hwmon sysfs attributes, causing warning about
duplicate sysfs entries upon reconnection.
This patch reworks the hwmon allocation to avoid device-managed
resource allocation, and uses the NVMe controller as parent for
the sysfs attributes.

Cc: Guenter Roeck <linux at roeck-us.net>
Signed-off-by: Hannes Reinecke <hare at suse.de>
Tested-by: Daniel Wagner <dwagner at suse.de>
---
 drivers/nvme/host/core.c  |  1 +
 drivers/nvme/host/hwmon.c | 31 +++++++++++++++++++++----------
 drivers/nvme/host/nvme.h  |  6 ++++++
 3 files changed, 28 insertions(+), 10 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index fff49e544fdf..3c6c77e44bf7 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -4419,6 +4419,7 @@ EXPORT_SYMBOL_GPL(nvme_start_ctrl);
 
 void nvme_uninit_ctrl(struct nvme_ctrl *ctrl)
 {
+	nvme_hwmon_exit(ctrl);
 	nvme_fault_inject_fini(&ctrl->fault_inject);
 	dev_pm_qos_hide_latency_tolerance(ctrl->device);
 	cdev_device_del(&ctrl->cdev, ctrl->device);
diff --git a/drivers/nvme/host/hwmon.c b/drivers/nvme/host/hwmon.c
index 552dbc04567b..8f9e96986780 100644
--- a/drivers/nvme/host/hwmon.c
+++ b/drivers/nvme/host/hwmon.c
@@ -223,12 +223,12 @@ static const struct hwmon_chip_info nvme_hwmon_chip_info = {
 
 int nvme_hwmon_init(struct nvme_ctrl *ctrl)
 {
-	struct device *dev = ctrl->dev;
+	struct device *dev = ctrl->device;
 	struct nvme_hwmon_data *data;
 	struct device *hwmon;
 	int err;
 
-	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
 	if (!data)
 		return 0;
 
@@ -237,19 +237,30 @@ int nvme_hwmon_init(struct nvme_ctrl *ctrl)
 
 	err = nvme_hwmon_get_smart_log(data);
 	if (err) {
-		dev_warn(ctrl->device,
-			"Failed to read smart log (error %d)\n", err);
-		devm_kfree(dev, data);
+		dev_warn(dev, "Failed to read smart log (error %d)\n", err);
+		kfree(data);
 		return err;
 	}
 
-	hwmon = devm_hwmon_device_register_with_info(dev, "nvme", data,
-						     &nvme_hwmon_chip_info,
-						     NULL);
+	hwmon = hwmon_device_register_with_info(dev, "nvme",
+						data, &nvme_hwmon_chip_info,
+						NULL);
 	if (IS_ERR(hwmon)) {
 		dev_warn(dev, "Failed to instantiate hwmon device\n");
-		devm_kfree(dev, data);
+		kfree(data);
 	}
-
+	ctrl->hwmon_device = hwmon;
 	return 0;
 }
+
+void nvme_hwmon_exit(struct nvme_ctrl *ctrl)
+{
+	if (ctrl->hwmon_device) {
+		struct nvme_hwmon_data *data =
+			dev_get_drvdata(ctrl->hwmon_device);
+
+		hwmon_device_unregister(ctrl->hwmon_device);
+		ctrl->hwmon_device = NULL;
+		kfree(data);
+	}
+}
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 88a6b97247f5..f51b942bb4f5 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -246,6 +246,9 @@ struct nvme_ctrl {
 	struct rw_semaphore namespaces_rwsem;
 	struct device ctrl_device;
 	struct device *device;	/* char device */
+#ifdef CONFIG_NVME_HWMON
+	struct device *hwmon_device;
+#endif
 	struct cdev cdev;
 	struct work_struct reset_work;
 	struct work_struct delete_work;
@@ -809,11 +812,14 @@ static inline struct nvme_ns *nvme_get_ns_from_dev(struct device *dev)
 
 #ifdef CONFIG_NVME_HWMON
 int nvme_hwmon_init(struct nvme_ctrl *ctrl);
+void nvme_hwmon_exit(struct nvme_ctrl *ctrl);
 #else
 static inline int nvme_hwmon_init(struct nvme_ctrl *ctrl)
 {
 	return 0;
 }
+
+static inline int nvme_hwmon_exit(struct nvme_ctrl *ctrl) {}
 #endif
 
 u32 nvme_command_effects(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
-- 
2.29.2



From dwagner at suse.de  Tue Jan 19 03:03:48 2021
From: dwagner at suse.de (Daniel Wagner)
Date: Tue, 19 Jan 2021 09:03:48 +0100
Subject: [PATCHv2] nvme/hwmon: rework to avoid devm allocation
In-Reply-To: <20210119064318.124415-1-hare@suse.de>
References: <20210119064318.124415-1-hare@suse.de>
Message-ID: <20210119080348.6bwitsqjjoujchuj@beryllium.lan>

On Tue, Jan 19, 2021 at 07:43:18AM +0100, Hannes Reinecke wrote:
> The original design to use device-managed resource allocation
> doesn't really work as the NVMe controller has a vastly different
> lifetime than the hwmon sysfs attributes, causing warning about
> duplicate sysfs entries upon reconnection.

To give Guenter a bit more info, it is not just warnings, user space is
able to crash the system by reading the hwmon entries when the nvme
device has been removed.

and here is the initial report and discussion on this:

  https://lore.kernel.org/linux-nvme/20201209213228.5044-1-ematsumiya at suse.de/


From damien.lemoal at wdc.com  Tue Jan 19 08:17:21 2021
From: damien.lemoal at wdc.com (Damien Le Moal)
Date: Tue, 19 Jan 2021 22:17:21 +0900
Subject: [PATCH v2 0/2] block: add zone write granularity limit
Message-ID: <20210119131723.1637853-1-damien.lemoal@wdc.com>

(resending as I forgot to add nvme and scsi lists and their
maintainers. My apologies for the noise)

The first patch in this series introduces the zone write granularity
queue limit to indicate the alignment constraint for write operations
into sequential zones of zoned block devices.

The second patch fixes adds the missing documentation for
zone_append_max_bytes to the sysfs block documentation.

Changes form v1:
* Fixed typo in patch 2

Damien Le Moal (2):
  block: introduce zone_write_granularity limit
  block: document zone_append_max_bytes attribute

 Documentation/block/queue-sysfs.rst | 13 +++++++++++++
 block/blk-settings.c                | 28 ++++++++++++++++++++++++++++
 block/blk-sysfs.c                   |  7 +++++++
 drivers/nvme/host/zns.c             |  1 +
 drivers/scsi/sd_zbc.c               | 10 ++++++++++
 include/linux/blkdev.h              |  3 +++
 6 files changed, 62 insertions(+)

-- 
2.29.2



From damien.lemoal at wdc.com  Tue Jan 19 08:17:22 2021
From: damien.lemoal at wdc.com (Damien Le Moal)
Date: Tue, 19 Jan 2021 22:17:22 +0900
Subject: [PATCH v2 1/2] block: introduce zone_write_granularity limit
In-Reply-To: <20210119131723.1637853-1-damien.lemoal@wdc.com>
References: <20210119131723.1637853-1-damien.lemoal@wdc.com>
Message-ID: <20210119131723.1637853-2-damien.lemoal@wdc.com>

Per ZBC and ZAC specifications, host-managed SMR hard-disks mandate that
all writes into sequential write required zones be aligned to the device
physical block size. However, NVMe ZNS does not have this constraint and
allows write operations into sequential zones to be logical block size
aligned. This inconsistency does not help with portability of software
across device types.
To solve this, introduce the zone_write_granularity queue limit to
indicate the alignment constraint, in bytes, of write operations into
zones of a zoned block device. This new limit is exported as a
read-only sysfs queue attribute and the helper
blk_queue_zone_write_granularity() introduced for drivers to set this
limit. The scsi disk driver is modified to use this helper to set
host-managed SMR disk zone write granularity to the disk physical block
size. The nvme driver zns support use this helper to set the new limit
to the logical block size of the zoned namespace.

Signed-off-by: Damien Le Moal <damien.lemoal at wdc.com>
---
 Documentation/block/queue-sysfs.rst |  7 +++++++
 block/blk-settings.c                | 28 ++++++++++++++++++++++++++++
 block/blk-sysfs.c                   |  7 +++++++
 drivers/nvme/host/zns.c             |  1 +
 drivers/scsi/sd_zbc.c               | 10 ++++++++++
 include/linux/blkdev.h              |  3 +++
 6 files changed, 56 insertions(+)

diff --git a/Documentation/block/queue-sysfs.rst b/Documentation/block/queue-sysfs.rst
index 2638d3446b79..c8bf8bc3c03a 100644
--- a/Documentation/block/queue-sysfs.rst
+++ b/Documentation/block/queue-sysfs.rst
@@ -273,4 +273,11 @@ devices are described in the ZBC (Zoned Block Commands) and ZAC
 do not support zone commands, they will be treated as regular block devices
 and zoned will report "none".
 
+zone_write_granularity (RO)
+---------------------------
+This indicates the alignment constraint, in bytes, for write operations in
+sequential zones of zoned block devices (devices with a zoned attributed
+that reports "host-managed" or "host-aware"). This value is always 0 for
+regular block devices.
+
 Jens Axboe <jens.axboe at oracle.com>, February 2009
diff --git a/block/blk-settings.c b/block/blk-settings.c
index 43990b1d148b..6be6ed9485e3 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -60,6 +60,7 @@ void blk_set_default_limits(struct queue_limits *lim)
 	lim->io_opt = 0;
 	lim->misaligned = 0;
 	lim->zoned = BLK_ZONED_NONE;
+	lim->zone_write_granularity = 0;
 }
 EXPORT_SYMBOL(blk_set_default_limits);
 
@@ -366,6 +367,31 @@ void blk_queue_physical_block_size(struct request_queue *q, unsigned int size)
 }
 EXPORT_SYMBOL(blk_queue_physical_block_size);
 
+/**
+ * blk_queue_zone_write_granularity - set zone write granularity for the queue
+ * @q:  the request queue for the zoned device
+ * @size:  the zone write granularity size, in bytes
+ *
+ * Description:
+ *   This should be set to the lowest possible size allowing to write in
+ *   sequential zones of a zoned block device.
+ */
+void blk_queue_zone_write_granularity(struct request_queue *q,
+				      unsigned int size)
+{
+	if (WARN_ON(!blk_queue_is_zoned(q)))
+		return;
+
+	q->limits.zone_write_granularity = size;
+
+	if (q->limits.zone_write_granularity < q->limits.logical_block_size)
+		q->limits.zone_write_granularity = q->limits.logical_block_size;
+
+	if (q->limits.zone_write_granularity < q->limits.io_min)
+		q->limits.zone_write_granularity = q->limits.io_min;
+}
+EXPORT_SYMBOL_GPL(blk_queue_zone_write_granularity);
+
 /**
  * blk_queue_alignment_offset - set physical block alignment offset
  * @q:	the request queue for the device
@@ -631,6 +657,8 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
 			t->discard_granularity;
 	}
 
+	t->zone_write_granularity = max(t->zone_write_granularity,
+					b->zone_write_granularity);
 	t->zoned = max(t->zoned, b->zoned);
 	return ret;
 }
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index b513f1683af0..7ea3dd4d876b 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -219,6 +219,11 @@ static ssize_t queue_write_zeroes_max_show(struct request_queue *q, char *page)
 		(unsigned long long)q->limits.max_write_zeroes_sectors << 9);
 }
 
+static ssize_t queue_zone_write_granularity_show(struct request_queue *q, char *page)
+{
+	return queue_var_show(q->limits.zone_write_granularity, page);
+}
+
 static ssize_t queue_zone_append_max_show(struct request_queue *q, char *page)
 {
 	unsigned long long max_sectors = q->limits.max_zone_append_sectors;
@@ -585,6 +590,7 @@ QUEUE_RO_ENTRY(queue_discard_zeroes_data, "discard_zeroes_data");
 QUEUE_RO_ENTRY(queue_write_same_max, "write_same_max_bytes");
 QUEUE_RO_ENTRY(queue_write_zeroes_max, "write_zeroes_max_bytes");
 QUEUE_RO_ENTRY(queue_zone_append_max, "zone_append_max_bytes");
+QUEUE_RO_ENTRY(queue_zone_write_granularity, "zone_write_granularity");
 
 QUEUE_RO_ENTRY(queue_zoned, "zoned");
 QUEUE_RO_ENTRY(queue_nr_zones, "nr_zones");
@@ -639,6 +645,7 @@ static struct attribute *queue_attrs[] = {
 	&queue_write_same_max_entry.attr,
 	&queue_write_zeroes_max_entry.attr,
 	&queue_zone_append_max_entry.attr,
+	&queue_zone_write_granularity_entry.attr,
 	&queue_nonrot_entry.attr,
 	&queue_zoned_entry.attr,
 	&queue_nr_zones_entry.attr,
diff --git a/drivers/nvme/host/zns.c b/drivers/nvme/host/zns.c
index 1dfe9a3500e3..f25311ccd996 100644
--- a/drivers/nvme/host/zns.c
+++ b/drivers/nvme/host/zns.c
@@ -113,6 +113,7 @@ int nvme_update_zone_info(struct nvme_ns *ns, unsigned lbaf)
 	blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, q);
 	blk_queue_max_open_zones(q, le32_to_cpu(id->mor) + 1);
 	blk_queue_max_active_zones(q, le32_to_cpu(id->mar) + 1);
+	blk_queue_zone_write_granularity(q, q->limits.logical_block_size);
 free_data:
 	kfree(id);
 	return status;
diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c
index cf07b7f93579..41d602f7e62e 100644
--- a/drivers/scsi/sd_zbc.c
+++ b/drivers/scsi/sd_zbc.c
@@ -789,6 +789,16 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf)
 	blk_queue_max_active_zones(q, 0);
 	nr_zones = round_up(sdkp->capacity, zone_blocks) >> ilog2(zone_blocks);
 
+	/*
+	 * Per ZBC and ZAC specifications, writes in sequential write required
+	 * zones of host-managed devices must be aligned to the device physical
+	 * block size.
+	 */
+	if (blk_queue_zoned_model(q) == BLK_ZONED_HM)
+		blk_queue_zone_write_granularity(q, sdkp->physical_block_size);
+	else
+		blk_queue_zone_write_granularity(q, sdkp->device->sector_size);
+
 	/* READ16/WRITE16 is mandatory for ZBC disks */
 	sdkp->device->use_16_for_rw = 1;
 	sdkp->device->use_10_for_rw = 0;
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index f94ee3089e01..011b3d2cd273 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -337,6 +337,7 @@ struct queue_limits {
 	unsigned int		max_zone_append_sectors;
 	unsigned int		discard_granularity;
 	unsigned int		discard_alignment;
+	unsigned int		zone_write_granularity;
 
 	unsigned short		max_segments;
 	unsigned short		max_integrity_segments;
@@ -1161,6 +1162,8 @@ extern void blk_queue_logical_block_size(struct request_queue *, unsigned int);
 extern void blk_queue_max_zone_append_sectors(struct request_queue *q,
 		unsigned int max_zone_append_sectors);
 extern void blk_queue_physical_block_size(struct request_queue *, unsigned int);
+void blk_queue_zone_write_granularity(struct request_queue *q,
+				      unsigned int size);
 extern void blk_queue_alignment_offset(struct request_queue *q,
 				       unsigned int alignment);
 void blk_queue_update_readahead(struct request_queue *q);
-- 
2.29.2



From damien.lemoal at wdc.com  Tue Jan 19 08:17:23 2021
From: damien.lemoal at wdc.com (Damien Le Moal)
Date: Tue, 19 Jan 2021 22:17:23 +0900
Subject: [PATCH v2 2/2] block: document zone_append_max_bytes attribute
In-Reply-To: <20210119131723.1637853-1-damien.lemoal@wdc.com>
References: <20210119131723.1637853-1-damien.lemoal@wdc.com>
Message-ID: <20210119131723.1637853-3-damien.lemoal@wdc.com>

The description of the zone_append_max_bytes sysfs queue attribute is
missing from Documentation/block/queue-sysfs.rst. Add it.

Signed-off-by: Damien Le Moal <damien.lemoal at wdc.com>
---
 Documentation/block/queue-sysfs.rst | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/block/queue-sysfs.rst b/Documentation/block/queue-sysfs.rst
index c8bf8bc3c03a..4dc7f0d499a8 100644
--- a/Documentation/block/queue-sysfs.rst
+++ b/Documentation/block/queue-sysfs.rst
@@ -261,6 +261,12 @@ For block drivers that support REQ_OP_WRITE_ZEROES, the maximum number of
 bytes that can be zeroed at once. The value 0 means that REQ_OP_WRITE_ZEROES
 is not supported.
 
+zone_append_max_bytes (RO)
+--------------------------
+This is the maximum number of bytes that can be written to a sequential
+zone of a zoned block device using a zone append write operation
+(REQ_OP_ZONE_APPEND). This value is always 0 for regular block devices.
+
 zoned (RO)
 ----------
 This indicates if the device is a zoned block device and the zone model of the
-- 
2.29.2



From mgurtovoy at nvidia.com  Tue Jan 19 09:20:25 2021
From: mgurtovoy at nvidia.com (Max Gurtovoy)
Date: Tue, 19 Jan 2021 16:20:25 +0200
Subject: [PATCH 1/1] nvme: update enumerations for status codes
In-Reply-To: <20210114175208.GA31438@lst.de>
References: <20210104125947.160984-1-mgurtovoy@nvidia.com>
 <20210114175208.GA31438@lst.de>
Message-ID: <a09653f8-1cdd-c62c-6eb6-b0a114b581a1@nvidia.com>


On 1/14/2021 7:52 PM, Christoph Hellwig wrote:
> Can we use this as a chance to resync with nvme-cli and have one
> version of the header that works for both?

Did you mean that both nvme-cli nvme.h files will be completely the same ?

nvme.h in nvme-cli has some weird cpu_to_le and le_to_cpu stuff and others..



From linux at roeck-us.net  Tue Jan 19 09:56:32 2021
From: linux at roeck-us.net (Guenter Roeck)
Date: Tue, 19 Jan 2021 06:56:32 -0800
Subject: [PATCHv2] nvme/hwmon: rework to avoid devm allocation
In-Reply-To: <20210119064318.124415-1-hare@suse.de>
References: <20210119064318.124415-1-hare@suse.de>
Message-ID: <20210119145632.GD54031@roeck-us.net>

On Tue, Jan 19, 2021 at 07:43:18AM +0100, Hannes Reinecke wrote:
> The original design to use device-managed resource allocation
> doesn't really work as the NVMe controller has a vastly different
> lifetime than the hwmon sysfs attributes, causing warning about
> duplicate sysfs entries upon reconnection.
> This patch reworks the hwmon allocation to avoid device-managed
> resource allocation, and uses the NVMe controller as parent for
> the sysfs attributes.

I don't really know enough about the nvme infrastructure to understand
this part of the change. Couple of questions: Why is the parent change
needed, and does the "sensors" command still work after this change ?

Guenter

> 
> Cc: Guenter Roeck <linux at roeck-us.net>
> Signed-off-by: Hannes Reinecke <hare at suse.de>
> Tested-by: Daniel Wagner <dwagner at suse.de>

Maybe add

Fixes: 400b6a7b13a3f ("nvme: Add hardware monitoring support")

> ---
>  drivers/nvme/host/core.c  |  1 +
>  drivers/nvme/host/hwmon.c | 31 +++++++++++++++++++++----------
>  drivers/nvme/host/nvme.h  |  6 ++++++
>  3 files changed, 28 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
> index fff49e544fdf..3c6c77e44bf7 100644
> --- a/drivers/nvme/host/core.c
> +++ b/drivers/nvme/host/core.c
> @@ -4419,6 +4419,7 @@ EXPORT_SYMBOL_GPL(nvme_start_ctrl);
>  
>  void nvme_uninit_ctrl(struct nvme_ctrl *ctrl)
>  {
> +	nvme_hwmon_exit(ctrl);
>  	nvme_fault_inject_fini(&ctrl->fault_inject);
>  	dev_pm_qos_hide_latency_tolerance(ctrl->device);
>  	cdev_device_del(&ctrl->cdev, ctrl->device);
> diff --git a/drivers/nvme/host/hwmon.c b/drivers/nvme/host/hwmon.c
> index 552dbc04567b..8f9e96986780 100644
> --- a/drivers/nvme/host/hwmon.c
> +++ b/drivers/nvme/host/hwmon.c
> @@ -223,12 +223,12 @@ static const struct hwmon_chip_info nvme_hwmon_chip_info = {
>  
>  int nvme_hwmon_init(struct nvme_ctrl *ctrl)
>  {
> -	struct device *dev = ctrl->dev;
> +	struct device *dev = ctrl->device;
>  	struct nvme_hwmon_data *data;
>  	struct device *hwmon;
>  	int err;
>  
> -	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
> +	data = kzalloc(sizeof(*data), GFP_KERNEL);
>  	if (!data)
>  		return 0;
>  
> @@ -237,19 +237,30 @@ int nvme_hwmon_init(struct nvme_ctrl *ctrl)
>  
>  	err = nvme_hwmon_get_smart_log(data);
>  	if (err) {
> -		dev_warn(ctrl->device,
> -			"Failed to read smart log (error %d)\n", err);
> -		devm_kfree(dev, data);
> +		dev_warn(dev, "Failed to read smart log (error %d)\n", err);
> +		kfree(data);
>  		return err;
>  	}
>  
> -	hwmon = devm_hwmon_device_register_with_info(dev, "nvme", data,
> -						     &nvme_hwmon_chip_info,
> -						     NULL);
> +	hwmon = hwmon_device_register_with_info(dev, "nvme",
> +						data, &nvme_hwmon_chip_info,
> +						NULL);
>  	if (IS_ERR(hwmon)) {
>  		dev_warn(dev, "Failed to instantiate hwmon device\n");
> -		devm_kfree(dev, data);
> +		kfree(data);
>  	}
> -
> +	ctrl->hwmon_device = hwmon;
>  	return 0;
>  }
> +
> +void nvme_hwmon_exit(struct nvme_ctrl *ctrl)
> +{
> +	if (ctrl->hwmon_device) {
> +		struct nvme_hwmon_data *data =
> +			dev_get_drvdata(ctrl->hwmon_device);
> +
> +		hwmon_device_unregister(ctrl->hwmon_device);
> +		ctrl->hwmon_device = NULL;
> +		kfree(data);
> +	}
> +}
> diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
> index 88a6b97247f5..f51b942bb4f5 100644
> --- a/drivers/nvme/host/nvme.h
> +++ b/drivers/nvme/host/nvme.h
> @@ -246,6 +246,9 @@ struct nvme_ctrl {
>  	struct rw_semaphore namespaces_rwsem;
>  	struct device ctrl_device;
>  	struct device *device;	/* char device */
> +#ifdef CONFIG_NVME_HWMON
> +	struct device *hwmon_device;
> +#endif
>  	struct cdev cdev;
>  	struct work_struct reset_work;
>  	struct work_struct delete_work;
> @@ -809,11 +812,14 @@ static inline struct nvme_ns *nvme_get_ns_from_dev(struct device *dev)
>  
>  #ifdef CONFIG_NVME_HWMON
>  int nvme_hwmon_init(struct nvme_ctrl *ctrl);
> +void nvme_hwmon_exit(struct nvme_ctrl *ctrl);
>  #else
>  static inline int nvme_hwmon_init(struct nvme_ctrl *ctrl)
>  {
>  	return 0;
>  }
> +
> +static inline int nvme_hwmon_exit(struct nvme_ctrl *ctrl) {}
>  #endif
>  
>  u32 nvme_command_effects(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
> -- 
> 2.29.2
> 


From marcorr at google.com  Tue Jan 19 12:53:36 2021
From: marcorr at google.com (Marc Orr)
Date: Tue, 19 Jan 2021 09:53:36 -0800
Subject: [PATCH] nvme: fix handling mapping failure
Message-ID: <20210119175336.4016923-1-marcorr@google.com>

This patch ensures that when `nvme_map_data()` fails to map the
addresses in a scatter/gather list:

* The addresses are not incorrectly unmapped. The underlying
scatter/gather code unmaps the addresses after detecting a failure.
Thus, unmapping them again in the driver is a bug.
* The DMA pool allocations are not deallocated when they were never
allocated.

The bug that motivated this patch was the following sequence, which
occurred within the NVMe driver, with the kernel flag `swiotlb=force`.

* NVMe driver calls dma_direct_map_sg()
* dma_direct_map_sg() fails part way through the scatter gather/list
* dma_direct_map_sg() calls dma_direct_unmap_sg() to unmap any entries
  succeeded.
* NVMe driver calls dma_direct_unmap_sg(), redundantly, leading to a
  double unmap, which is a bug.

Before this patch, I observed intermittent application- and VM-level
failures when running a benchmark, fio, in an AMD SEV guest. This patch
resolves the failures.

Tested-by: Marc Orr <marcorr at google.com>
Cc: stable at vger.kernel.org
Signed-off-by: Marc Orr <marcorr at google.com>
---
 drivers/nvme/host/pci.c | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 9b1fc8633cfe..8b504ed08321 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -543,11 +543,14 @@ static void nvme_unmap_data(struct nvme_dev *dev, struct request *req)
 
 	WARN_ON_ONCE(!iod->nents);
 
-	if (is_pci_p2pdma_page(sg_page(iod->sg)))
-		pci_p2pdma_unmap_sg(dev->dev, iod->sg, iod->nents,
-				    rq_dma_dir(req));
-	else
-		dma_unmap_sg(dev->dev, iod->sg, iod->nents, rq_dma_dir(req));
+	if (!dma_mapping_error(dev->dev, iod->first_dma)) {
+		if (is_pci_p2pdma_page(sg_page(iod->sg)))
+			pci_p2pdma_unmap_sg(dev->dev, iod->sg, iod->nents,
+					    rq_dma_dir(req));
+		else
+			dma_unmap_sg(dev->dev, iod->sg, iod->nents,
+				     rq_dma_dir(req));
+	}
 
 
 	if (iod->npages == 0)
@@ -836,8 +839,11 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
 	else
 		nr_mapped = dma_map_sg_attrs(dev->dev, iod->sg, iod->nents,
 					     rq_dma_dir(req), DMA_ATTR_NO_WARN);
-	if (!nr_mapped)
+	if (!nr_mapped) {
+		iod->first_dma = DMA_MAPPING_ERROR;
+		iod->npages = -1;
 		goto out;
+	}
 
 	iod->use_sgl = nvme_pci_use_sgls(dev, req);
 	if (iod->use_sgl)
-- 
2.30.0.284.gd98b1dd5eaa7-goog



From hch at lst.de  Tue Jan 19 13:00:24 2021
From: hch at lst.de (Christoph Hellwig)
Date: Tue, 19 Jan 2021 19:00:24 +0100
Subject: [PATCH] nvme: fix handling mapping failure
In-Reply-To: <20210119175336.4016923-1-marcorr@google.com>
References: <20210119175336.4016923-1-marcorr@google.com>
Message-ID: <20210119180024.GA28024@lst.de>

On Tue, Jan 19, 2021 at 09:53:36AM -0800, Marc Orr wrote:
> This patch ensures that when `nvme_map_data()` fails to map the
> addresses in a scatter/gather list:
> 
> * The addresses are not incorrectly unmapped. The underlying
> scatter/gather code unmaps the addresses after detecting a failure.
> Thus, unmapping them again in the driver is a bug.
> * The DMA pool allocations are not deallocated when they were never
> allocated.
> 
> The bug that motivated this patch was the following sequence, which
> occurred within the NVMe driver, with the kernel flag `swiotlb=force`.
> 
> * NVMe driver calls dma_direct_map_sg()
> * dma_direct_map_sg() fails part way through the scatter gather/list
> * dma_direct_map_sg() calls dma_direct_unmap_sg() to unmap any entries
>   succeeded.
> * NVMe driver calls dma_direct_unmap_sg(), redundantly, leading to a
>   double unmap, which is a bug.
> 
> Before this patch, I observed intermittent application- and VM-level
> failures when running a benchmark, fio, in an AMD SEV guest. This patch
> resolves the failures.

I think the right way to fix this is to just do a proper unwind insted
of calling a catchall function.  Can you try this patch?

diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 25456d02eddb8c..47d7075053b6b2 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -842,7 +842,7 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
 	sg_init_table(iod->sg, blk_rq_nr_phys_segments(req));
 	iod->nents = blk_rq_map_sg(req->q, req, iod->sg);
 	if (!iod->nents)
-		goto out;
+		goto out_free_sg;
 
 	if (is_pci_p2pdma_page(sg_page(iod->sg)))
 		nr_mapped = pci_p2pdma_map_sg_attrs(dev->dev, iod->sg,
@@ -851,16 +851,25 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
 		nr_mapped = dma_map_sg_attrs(dev->dev, iod->sg, iod->nents,
 					     rq_dma_dir(req), DMA_ATTR_NO_WARN);
 	if (!nr_mapped)
-		goto out;
+		goto out_free_sg;
 
 	iod->use_sgl = nvme_pci_use_sgls(dev, req);
 	if (iod->use_sgl)
 		ret = nvme_pci_setup_sgls(dev, req, &cmnd->rw, nr_mapped);
 	else
 		ret = nvme_pci_setup_prps(dev, req, &cmnd->rw);
-out:
 	if (ret != BLK_STS_OK)
-		nvme_unmap_data(dev, req);
+		goto out_dma_unmap;
+	return BLK_STS_OK;
+
+out_dma_unmap:
+	if (is_pci_p2pdma_page(sg_page(iod->sg)))
+		pci_p2pdma_unmap_sg(dev->dev, iod->sg, iod->nents,
+				    rq_dma_dir(req));
+	else
+		dma_unmap_sg(dev->dev, iod->sg, iod->nents, rq_dma_dir(req));
+out_free_sg:
+	mempool_free(iod->sg, dev->iod_mempool);
 	return ret;
 }
 


From kbusch at kernel.org  Tue Jan 19 13:28:38 2021
From: kbusch at kernel.org (Keith Busch)
Date: Wed, 20 Jan 2021 03:28:38 +0900
Subject: [PATCH V3 3/3] nvme: retry commands based on ACRE flag
In-Reply-To: <20210118174051.GA8542@lst.de>
References: <20210114133110.20779-1-minwoo.im.dev@gmail.com>
 <20210114133110.20779-4-minwoo.im.dev@gmail.com>
 <20210115170412.GA1515933@dhcp-10-100-145-180.wdc.com>
 <20210115182602.GA2822@localhost.localdomain>
 <20210118174051.GA8542@lst.de>
Message-ID: <20210119180535.GA1520627@dhcp-10-100-145-180.wdc.com>

On Mon, Jan 18, 2021 at 06:40:51PM +0100, Christoph Hellwig wrote:
> On Sat, Jan 16, 2021 at 03:26:02AM +0900, Minwoo Im wrote:
> > > I am not sure we should ignore the FAILFAST for non-path errors. If we
> > > need retryable admin commands, we should let the driver provide a way
> > > for callers to dispatch requests without that flag.
> > 
> > Understood.  I thought the opposite way about FAILFAST in case with
> > acre, if device is enabled with acre, all commands would be retried
> > regardless to FAILFAST...  Thanks for pointing that out!
> > 
> > How do you think which one is right choice to go with if a user-space
> > application(e.g., nvme-cli) wants a command to be retired in case of
> > ACRE && Error && !DNR:
> > 
> >   - User-space application should figure out !DNR and retry the command.
> >     (Maybe we are not able to easily figure out exact status code from
> >     the user-space application by the return value).
> > 
> >   - Driver should retry the command right before putting result up to
> >     the user-space even it's a FAILFAST request.
> > 
> > Thanks,
> 
> We could come up with a version of the ioctls that use the normal
> retry mechanisms.  nvme_passthru_cmd64 has two reserved fields we
> could use for UAPI flags like this.

Yeah, I'm totally okay with adding driver control flags for this sort of
behavior.

For the moment, the ioctl interface has always been 1:1 for commands
submitted to completions received, so all user space applications using
this should have been prepared to receive unfiltered status back and
handle retries on their own.


From hare at suse.de  Tue Jan 19 14:07:46 2021
From: hare at suse.de (Hannes Reinecke)
Date: Tue, 19 Jan 2021 20:07:46 +0100
Subject: [PATCHv2] nvme/hwmon: rework to avoid devm allocation
In-Reply-To: <20210119145632.GD54031@roeck-us.net>
References: <20210119064318.124415-1-hare@suse.de>
 <20210119145632.GD54031@roeck-us.net>
Message-ID: <1093bedb-9b6d-b365-85d0-de8ef7eceb95@suse.de>

On 1/19/21 3:56 PM, Guenter Roeck wrote:
> On Tue, Jan 19, 2021 at 07:43:18AM +0100, Hannes Reinecke wrote:
>> The original design to use device-managed resource allocation
>> doesn't really work as the NVMe controller has a vastly different
>> lifetime than the hwmon sysfs attributes, causing warning about
>> duplicate sysfs entries upon reconnection.
>> This patch reworks the hwmon allocation to avoid device-managed
>> resource allocation, and uses the NVMe controller as parent for
>> the sysfs attributes.
> 
> I don't really know enough about the nvme infrastructure to understand
> this part of the change. Couple of questions: Why is the parent change
> needed, and does the "sensors" command still work after this change ?
> 
Problem is that it's not really a 'new' infrastructure, it's 
NVMe-over-fabrics, which behaves slightly different from the PCI-based 
NVMe devices.
In particular we can and will have connectivity failures, requiring the 
controller to be reset or recreated.
And as the hwmon sysfs attributes were never removed correctly in the 
first place we're seeing these errors.
It isn't easily recreated on PCI devices as the sysfs attributes will 
only ever be removed on shutdown (or module unload).
So I fear the issue was with us since day-1.

As for the parent change: for fabrics the '->dev' device points to a 
static nvmf_device, which is identical for every fabrics controller.
So you really need to use the actual device in '->device' to have a 
different parent device for different controllers.
So for PCI that means that the 'hwmon' device moved one element down 
(from the PCI device to the nvme controller).
But shouldn't make much of a difference; I'll check on if 'sensors' 
continues to work.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare at suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 N?rnberg
HRB 36809 (AG N?rnberg), Gesch?ftsf?hrer: Felix Imend?rffer


From ematsumiya at suse.de  Tue Jan 19 17:18:49 2021
From: ematsumiya at suse.de (Enzo Matsumiya)
Date: Tue, 19 Jan 2021 19:18:49 -0300
Subject: [PATCHv2] nvme/hwmon: rework to avoid devm allocation
In-Reply-To: <20210119064318.124415-1-hare@suse.de>
References: <20210119064318.124415-1-hare@suse.de>
Message-ID: <20210119221849.npokdza7linj5ocd@hyori>

On 01/19, Hannes Reinecke wrote:
>The original design to use device-managed resource allocation
>doesn't really work as the NVMe controller has a vastly different
>lifetime than the hwmon sysfs attributes, causing warning about
>duplicate sysfs entries upon reconnection.
>This patch reworks the hwmon allocation to avoid device-managed
>resource allocation, and uses the NVMe controller as parent for
>the sysfs attributes.

Works fine on my NVMe-oF/TCP setup now. Thanks.

>Cc: Guenter Roeck <linux at roeck-us.net>
>Signed-off-by: Hannes Reinecke <hare at suse.de>
>Tested-by: Daniel Wagner <dwagner at suse.de>

Tested-by: Enzo Matsumiya <ematsumiya at suse.de>


Cheers,

Enzo


From marcorr at google.com  Tue Jan 19 18:12:25 2021
From: marcorr at google.com (Marc Orr)
Date: Tue, 19 Jan 2021 15:12:25 -0800
Subject: [PATCH] nvme: fix handling mapping failure
In-Reply-To: <20210119180024.GA28024@lst.de>
References: <20210119175336.4016923-1-marcorr@google.com>
 <20210119180024.GA28024@lst.de>
Message-ID: <CAA03e5GeGRLcLzp8d6pOC7UnQq9mZYzgW9rQgV3XHMb5gfsLWQ@mail.gmail.com>

On Tue, Jan 19, 2021 at 10:00 AM Christoph Hellwig <hch at lst.de> wrote:
>
> On Tue, Jan 19, 2021 at 09:53:36AM -0800, Marc Orr wrote:
> > This patch ensures that when `nvme_map_data()` fails to map the
> > addresses in a scatter/gather list:
> >
> > * The addresses are not incorrectly unmapped. The underlying
> > scatter/gather code unmaps the addresses after detecting a failure.
> > Thus, unmapping them again in the driver is a bug.
> > * The DMA pool allocations are not deallocated when they were never
> > allocated.
> >
> > The bug that motivated this patch was the following sequence, which
> > occurred within the NVMe driver, with the kernel flag `swiotlb=force`.
> >
> > * NVMe driver calls dma_direct_map_sg()
> > * dma_direct_map_sg() fails part way through the scatter gather/list
> > * dma_direct_map_sg() calls dma_direct_unmap_sg() to unmap any entries
> >   succeeded.
> > * NVMe driver calls dma_direct_unmap_sg(), redundantly, leading to a
> >   double unmap, which is a bug.
> >
> > Before this patch, I observed intermittent application- and VM-level
> > failures when running a benchmark, fio, in an AMD SEV guest. This patch
> > resolves the failures.
>
> I think the right way to fix this is to just do a proper unwind insted
> of calling a catchall function.  Can you try this patch?

Done. It works great, thanks! Shall I send out a v2 with what you've proposed?

> diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
> index 25456d02eddb8c..47d7075053b6b2 100644
> --- a/drivers/nvme/host/pci.c
> +++ b/drivers/nvme/host/pci.c
> @@ -842,7 +842,7 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
>         sg_init_table(iod->sg, blk_rq_nr_phys_segments(req));
>         iod->nents = blk_rq_map_sg(req->q, req, iod->sg);
>         if (!iod->nents)
> -               goto out;
> +               goto out_free_sg;
>
>         if (is_pci_p2pdma_page(sg_page(iod->sg)))
>                 nr_mapped = pci_p2pdma_map_sg_attrs(dev->dev, iod->sg,
> @@ -851,16 +851,25 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
>                 nr_mapped = dma_map_sg_attrs(dev->dev, iod->sg, iod->nents,
>                                              rq_dma_dir(req), DMA_ATTR_NO_WARN);
>         if (!nr_mapped)
> -               goto out;
> +               goto out_free_sg;
>
>         iod->use_sgl = nvme_pci_use_sgls(dev, req);
>         if (iod->use_sgl)
>                 ret = nvme_pci_setup_sgls(dev, req, &cmnd->rw, nr_mapped);
>         else
>                 ret = nvme_pci_setup_prps(dev, req, &cmnd->rw);
> -out:
>         if (ret != BLK_STS_OK)
> -               nvme_unmap_data(dev, req);
> +               goto out_dma_unmap;
> +       return BLK_STS_OK;
> +
> +out_dma_unmap:
> +       if (is_pci_p2pdma_page(sg_page(iod->sg)))
> +               pci_p2pdma_unmap_sg(dev->dev, iod->sg, iod->nents,
> +                                   rq_dma_dir(req));
> +       else
> +               dma_unmap_sg(dev->dev, iod->sg, iod->nents, rq_dma_dir(req));

Do you think it's worth hoisting this sg unmap snippet into a helper
that can be called from both here, as well as nvme_unmap_data()?

> +out_free_sg:
> +       mempool_free(iod->sg, dev->iod_mempool);
>         return ret;
>  }
>


From minwoo.im.dev at gmail.com  Tue Jan 19 19:52:36 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Wed, 20 Jan 2021 09:52:36 +0900
Subject: [PATCH V3 3/3] nvme: retry commands based on ACRE flag
In-Reply-To: <20210119180535.GA1520627@dhcp-10-100-145-180.wdc.com>
References: <20210114133110.20779-1-minwoo.im.dev@gmail.com>
 <20210114133110.20779-4-minwoo.im.dev@gmail.com>
 <20210115170412.GA1515933@dhcp-10-100-145-180.wdc.com>
 <20210115182602.GA2822@localhost.localdomain>
 <20210118174051.GA8542@lst.de>
 <20210119180535.GA1520627@dhcp-10-100-145-180.wdc.com>
Message-ID: <20210120005236.GD4205@localhost.localdomain>

On 21-01-20 03:28:38, Keith Busch wrote:
> On Mon, Jan 18, 2021 at 06:40:51PM +0100, Christoph Hellwig wrote:
> > On Sat, Jan 16, 2021 at 03:26:02AM +0900, Minwoo Im wrote:
> > > > I am not sure we should ignore the FAILFAST for non-path errors. If we
> > > > need retryable admin commands, we should let the driver provide a way
> > > > for callers to dispatch requests without that flag.
> > > 
> > > Understood.  I thought the opposite way about FAILFAST in case with
> > > acre, if device is enabled with acre, all commands would be retried
> > > regardless to FAILFAST...  Thanks for pointing that out!
> > > 
> > > How do you think which one is right choice to go with if a user-space
> > > application(e.g., nvme-cli) wants a command to be retired in case of
> > > ACRE && Error && !DNR:
> > > 
> > >   - User-space application should figure out !DNR and retry the command.
> > >     (Maybe we are not able to easily figure out exact status code from
> > >     the user-space application by the return value).
> > > 
> > >   - Driver should retry the command right before putting result up to
> > >     the user-space even it's a FAILFAST request.
> > > 
> > > Thanks,
> > 
> > We could come up with a version of the ioctls that use the normal
> > retry mechanisms.  nvme_passthru_cmd64 has two reserved fields we
> > could use for UAPI flags like this.
> 
> Yeah, I'm totally okay with adding driver control flags for this sort of
> behavior.
> 
> For the moment, the ioctl interface has always been 1:1 for commands
> submitted to completions received, so all user space applications using
> this should have been prepared to receive unfiltered status back and
> handle retries on their own.

Thanks Keith for your feedback!


From Chaitanya.Kulkarni at wdc.com  Tue Jan 19 22:08:32 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Wed, 20 Jan 2021 03:08:32 +0000
Subject: Problem with SPCC 256GB NVMe 1.3 drive - refcount_t: underflow;
 use-after-free.
References: <f50bc59c-db11-bb44-55be-7b9db1119872@comcast.net>
 <BYAPR04MB49659C0F0F0E11D166B31E0586A40@BYAPR04MB4965.namprd04.prod.outlook.com>
 <a4c75497-d170-1e0f-8608-282231ff3a8e@comcast.net>
Message-ID: <BYAPR04MB496542BEF594F0380F7D41CF86A20@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/18/21 10:33 AM, Bradley Chapman wrote:
> Good afternoon!
>
> On 1/17/21 11:36 PM, Chaitanya Kulkarni wrote:
>> On 1/17/21 11:05 AM, Bradley Chapman wrote:
>>> [ 2836.554298] nvme nvme1: I/O 415 QID 3 timeout, disable controller
>>> [ 2836.672064] blk_update_request: I/O error, dev nvme1n1, sector 16350
>>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>>> [ 2836.672072] blk_update_request: I/O error, dev nvme1n1, sector 16093
>>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>>> [ 2836.672074] blk_update_request: I/O error, dev nvme1n1, sector 15836
>>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>>> [ 2836.672076] blk_update_request: I/O error, dev nvme1n1, sector 15579
>>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>>> [ 2836.672078] blk_update_request: I/O error, dev nvme1n1, sector 15322
>>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>>> [ 2836.672080] blk_update_request: I/O error, dev nvme1n1, sector 15065
>>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>>> [ 2836.672082] blk_update_request: I/O error, dev nvme1n1, sector 14808
>>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>>> [ 2836.672083] blk_update_request: I/O error, dev nvme1n1, sector 14551
>>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>>> [ 2836.672085] blk_update_request: I/O error, dev nvme1n1, sector 14294
>>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>>> [ 2836.672087] blk_update_request: I/O error, dev nvme1n1, sector 14037
>>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>>> [ 2836.672121] nvme nvme1: failed to mark controller live state
>>> [ 2836.672123] nvme nvme1: Removing after probe failure status: -19
>>> [ 2836.689016] Aborting journal on device dm-0-8.
>>> [ 2836.689024] Buffer I/O error on dev dm-0, logical block 25198592,
>>> lost sync page write
>>> [ 2836.689027] JBD2: Error -5 detected when updating journal superblock
>>> for dm-0-8.
>> Without the knowledge of fs mount/format command I can only suspect that
>> super
>> block zeroing issued with write-zeroes request is translated into
>> REQ_OP_WRITE_ZEROES which controller is not able to process resulting in
>> the error. This analysis maybe wrong.
>>
>> Can you please share following details :-
>>
>> nvme id-ns /dev/nvme0n1 -H (we are interested in oncs part here)
> I ran the requested command against /dev/nvme1n1 (since /dev/nvme0n1 
> works perfectly so far) and here is the result:
Sorry my bad it suppose to be nvme id-ctrl /dev/nvme0n1 -H
>> Also for above device what is the value for the queue block write-zeroes
>>
>> parameter that is present in the
>> /sys/block/<nvmeXnY>/queue/write_zeroes_max_bytes ?
> $ cat /sys/block/nvme1n1/queue/write_zeroes_max_bytes
> 131584
So write-zeroes is configured from the setup.
>> You can also try blkdiscard -z 0 -l 1024 /dev/<nvmeXnY> to see if the
>> problem is with
>> write zeroes.
> # blkdiscard -z -l 1024 /dev/nvme1n1
> blkdiscard: /dev/nvme1n1: BLKZEROOUT ioctl failed: Device or resource busy
This is exactly what I thought, we need to add a quirk for this model
and make sure
we don't set the write-zeroes support and make blk-lib emulate the
write-zeroes.
>> Also can you please also try the latest nvme tree branch nvme-5.11 ?
>>
> Where do I get that code from? Is it already in the 5.11-rc tree or do I 
> need to look somewhere else? I checked https://github.com/linux-nvme but 
> I did not see it there.
Here is the link :-git://git.infradead.org/nvme.git
Branch 5.12.
> Brad
>



From Chaitanya.Kulkarni at wdc.com  Wed Jan 20 00:09:39 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Wed, 20 Jan 2021 05:09:39 +0000
Subject: [PATCH 1/1] nvme: update enumerations for status codes
References: <20210104125947.160984-1-mgurtovoy@nvidia.com>
Message-ID: <BYAPR04MB4965E1DC0180C2E5789E505186A20@BYAPR04MB4965.namprd04.prod.outlook.com>

Max,
On 1/4/21 04:59, Max Gurtovoy wrote:
> All the updates are mentioned in the ratified NVMe 1.4 spec.
>
> Signed-off-by: Max Gurtovoy <mgurtovoy at nvidia.com>
> ---
I'm not against keeping the header file up to date with the spec,
but should we add the error status into the kernel code even if
we are not using it in the host/target driver ?

Here we add 24 lines which we have not used at all.
>  include/linux/nvme.h | 24 ++++++++++++++++++++----
>  1 file changed, 20 insertions(+), 4 deletions(-)
>
Regarding the nvme-cli this is much needed a sync since it does
decode all the errors if I'm not wrong.


From linux at roeck-us.net  Wed Jan 20 00:54:30 2021
From: linux at roeck-us.net (Guenter Roeck)
Date: Tue, 19 Jan 2021 21:54:30 -0800
Subject: [PATCHv2] nvme/hwmon: rework to avoid devm allocation
In-Reply-To: <1093bedb-9b6d-b365-85d0-de8ef7eceb95@suse.de>
References: <20210119064318.124415-1-hare@suse.de>
 <20210119145632.GD54031@roeck-us.net>
 <1093bedb-9b6d-b365-85d0-de8ef7eceb95@suse.de>
Message-ID: <efddf566-a5a1-cda0-5fec-5e8a1d6bffb3@roeck-us.net>

On 1/19/21 11:07 AM, Hannes Reinecke wrote:
> On 1/19/21 3:56 PM, Guenter Roeck wrote:
>> On Tue, Jan 19, 2021 at 07:43:18AM +0100, Hannes Reinecke wrote:
>>> The original design to use device-managed resource allocation
>>> doesn't really work as the NVMe controller has a vastly different
>>> lifetime than the hwmon sysfs attributes, causing warning about
>>> duplicate sysfs entries upon reconnection.
>>> This patch reworks the hwmon allocation to avoid device-managed
>>> resource allocation, and uses the NVMe controller as parent for
>>> the sysfs attributes.
>>
>> I don't really know enough about the nvme infrastructure to understand
>> this part of the change. Couple of questions: Why is the parent change
>> needed, and does the "sensors" command still work after this change ?
>>
> Problem is that it's not really a 'new' infrastructure, it's NVMe-over-fabrics, which behaves slightly different from the PCI-based NVMe devices.
> In particular we can and will have connectivity failures, requiring the controller to be reset or recreated.
> And as the hwmon sysfs attributes were never removed correctly in the first place we're seeing these errors.
> It isn't easily recreated on PCI devices as the sysfs attributes will only ever be removed on shutdown (or module unload).
> So I fear the issue was with us since day-1.
> 
I understand; that is why I suggested to add a Fixes: tag.

> As for the parent change: for fabrics the '->dev' device points to a static nvmf_device, which is identical for every fabrics controller.
> So you really need to use the actual device in '->device' to have a different parent device for different controllers.
> So for PCI that means that the 'hwmon' device moved one element down (from the PCI device to the nvme controller).
> But shouldn't make much of a difference; I'll check on if 'sensors' continues to work.
> 

It needs lm-sensors version 3.5.0 or later. Older versions
don't support a device hierarchy.

Guenter


From hch at lst.de  Wed Jan 20 04:49:13 2021
From: hch at lst.de (Christoph Hellwig)
Date: Wed, 20 Jan 2021 10:49:13 +0100
Subject: fix error unwinding in nvme_map_data
Message-ID: <20210120094915.3198346-1-hch@lst.de>

Hi all,

this series fixes the error unwinding in nvme_map_data after a report
from Marc that we see unmaps of not actually mapped data in AMD SEV
environments (which happen to be fairly DMA constained).


From hch at lst.de  Wed Jan 20 04:49:14 2021
From: hch at lst.de (Christoph Hellwig)
Date: Wed, 20 Jan 2021 10:49:14 +0100
Subject: [PATCH 1/2] nvme-pci: refactor nvme_unmap_data
In-Reply-To: <20210120094915.3198346-1-hch@lst.de>
References: <20210120094915.3198346-1-hch@lst.de>
Message-ID: <20210120094915.3198346-2-hch@lst.de>

Split out three helpers from nvme_unmap_data that will allow finer grained
unwinding from nvme_map_data.

Signed-off-by: Christoph Hellwig <hch at lst.de>
---
 drivers/nvme/host/pci.c | 77 ++++++++++++++++++++++++++---------------
 1 file changed, 49 insertions(+), 28 deletions(-)

diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 25456d02eddb8c..e29ece9e4d4b8e 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -543,50 +543,71 @@ static inline bool nvme_pci_use_sgls(struct nvme_dev *dev, struct request *req)
 	return true;
 }
 
-static void nvme_unmap_data(struct nvme_dev *dev, struct request *req)
+static void nvme_free_prps(struct nvme_dev *dev, struct request *req)
 {
-	struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
 	const int last_prp = NVME_CTRL_PAGE_SIZE / sizeof(__le64) - 1;
-	dma_addr_t dma_addr = iod->first_dma, next_dma_addr;
+	struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
+	dma_addr_t dma_addr = iod->first_dma;
 	int i;
 
-	if (iod->dma_len) {
-		dma_unmap_page(dev->dev, dma_addr, iod->dma_len,
-			       rq_dma_dir(req));
-		return;
+	for (i = 0; i < iod->npages; i++) {
+		__le64 *prp_list = nvme_pci_iod_list(req)[i];
+		dma_addr_t next_dma_addr = le64_to_cpu(prp_list[last_prp]);
+
+		dma_pool_free(dev->prp_page_pool, prp_list, dma_addr);
+		dma_addr = next_dma_addr;
 	}
 
-	WARN_ON_ONCE(!iod->nents);
+}
 
-	if (is_pci_p2pdma_page(sg_page(iod->sg)))
-		pci_p2pdma_unmap_sg(dev->dev, iod->sg, iod->nents,
-				    rq_dma_dir(req));
-	else
-		dma_unmap_sg(dev->dev, iod->sg, iod->nents, rq_dma_dir(req));
+static void nvme_free_sgls(struct nvme_dev *dev, struct request *req)
+{
+	const int last_sg = SGES_PER_PAGE - 1;
+	struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
+	dma_addr_t dma_addr = iod->first_dma;
+	int i;
 
+	for (i = 0; i < iod->npages; i++) {
+		struct nvme_sgl_desc *sg_list = nvme_pci_iod_list(req)[i];
+		dma_addr_t next_dma_addr = le64_to_cpu((sg_list[last_sg]).addr);
 
-	if (iod->npages == 0)
-		dma_pool_free(dev->prp_small_pool, nvme_pci_iod_list(req)[0],
-			dma_addr);
+		dma_pool_free(dev->prp_page_pool, sg_list, dma_addr);
+		dma_addr = next_dma_addr;
+	}
 
-	for (i = 0; i < iod->npages; i++) {
-		void *addr = nvme_pci_iod_list(req)[i];
+}
 
-		if (iod->use_sgl) {
-			struct nvme_sgl_desc *sg_list = addr;
+static void nvme_unmap_sg(struct nvme_dev *dev, struct request *req)
+{
+	struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
 
-			next_dma_addr =
-			    le64_to_cpu((sg_list[SGES_PER_PAGE - 1]).addr);
-		} else {
-			__le64 *prp_list = addr;
+	if (is_pci_p2pdma_page(sg_page(iod->sg)))
+		pci_p2pdma_unmap_sg(dev->dev, iod->sg, iod->nents,
+				    rq_dma_dir(req));
+	else
+		dma_unmap_sg(dev->dev, iod->sg, iod->nents, rq_dma_dir(req));
+}
 
-			next_dma_addr = le64_to_cpu(prp_list[last_prp]);
-		}
+static void nvme_unmap_data(struct nvme_dev *dev, struct request *req)
+{
+	struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
 
-		dma_pool_free(dev->prp_page_pool, addr, dma_addr);
-		dma_addr = next_dma_addr;
+	if (iod->dma_len) {
+		dma_unmap_page(dev->dev, iod->first_dma, iod->dma_len,
+			       rq_dma_dir(req));
+		return;
 	}
 
+	WARN_ON_ONCE(!iod->nents);
+
+	nvme_unmap_sg(dev, req);
+	if (iod->npages == 0)
+		dma_pool_free(dev->prp_small_pool, nvme_pci_iod_list(req)[0],
+			      iod->first_dma);
+	else if (iod->use_sgl)
+		nvme_free_sgls(dev, req);
+	else
+		nvme_free_prps(dev, req);
 	mempool_free(iod->sg, dev->iod_mempool);
 }
 
-- 
2.29.2



From hch at lst.de  Wed Jan 20 04:49:15 2021
From: hch at lst.de (Christoph Hellwig)
Date: Wed, 20 Jan 2021 10:49:15 +0100
Subject: [PATCH 2/2] nvme-pci: fix error unwind in nvme_map_data
In-Reply-To: <20210120094915.3198346-1-hch@lst.de>
References: <20210120094915.3198346-1-hch@lst.de>
Message-ID: <20210120094915.3198346-3-hch@lst.de>

Properly unwind step by step using refactored helpers from nvme_unmap_data
to avoid a potential double dma_unmap on a mapping failure.

Reported-by: Marc Orr <marcorr at google.com>
Signed-off-by: Christoph Hellwig <hch at lst.de>
---
 drivers/nvme/host/pci.c | 28 ++++++++++++++++++----------
 1 file changed, 18 insertions(+), 10 deletions(-)

diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index e29ece9e4d4b8e..4e93d1b52df202 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -683,7 +683,7 @@ static blk_status_t nvme_pci_setup_prps(struct nvme_dev *dev,
 			__le64 *old_prp_list = prp_list;
 			prp_list = dma_pool_alloc(pool, GFP_ATOMIC, &prp_dma);
 			if (!prp_list)
-				return BLK_STS_RESOURCE;
+				goto free_prps;
 			list[iod->npages++] = prp_list;
 			prp_list[0] = old_prp_list[i - 1];
 			old_prp_list[i - 1] = cpu_to_le64(prp_dma);
@@ -703,14 +703,14 @@ static blk_status_t nvme_pci_setup_prps(struct nvme_dev *dev,
 		dma_addr = sg_dma_address(sg);
 		dma_len = sg_dma_len(sg);
 	}
-
 done:
 	cmnd->dptr.prp1 = cpu_to_le64(sg_dma_address(iod->sg));
 	cmnd->dptr.prp2 = cpu_to_le64(iod->first_dma);
-
 	return BLK_STS_OK;
-
- bad_sgl:
+free_prps:
+	nvme_free_prps(dev, req);
+	return BLK_STS_RESOURCE;
+bad_sgl:
 	WARN(DO_ONCE(nvme_print_sgl, iod->sg, iod->nents),
 			"Invalid SGL for payload:%d nents:%d\n",
 			blk_rq_payload_bytes(req), iod->nents);
@@ -782,7 +782,7 @@ static blk_status_t nvme_pci_setup_sgls(struct nvme_dev *dev,
 
 			sg_list = dma_pool_alloc(pool, GFP_ATOMIC, &sgl_dma);
 			if (!sg_list)
-				return BLK_STS_RESOURCE;
+				goto free_sgls;
 
 			i = 0;
 			nvme_pci_iod_list(req)[iod->npages++] = sg_list;
@@ -795,6 +795,9 @@ static blk_status_t nvme_pci_setup_sgls(struct nvme_dev *dev,
 	} while (--entries > 0);
 
 	return BLK_STS_OK;
+free_sgls:
+	nvme_free_sgls(dev, req);
+	return BLK_STS_RESOURCE;
 }
 
 static blk_status_t nvme_setup_prp_simple(struct nvme_dev *dev,
@@ -863,7 +866,7 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
 	sg_init_table(iod->sg, blk_rq_nr_phys_segments(req));
 	iod->nents = blk_rq_map_sg(req->q, req, iod->sg);
 	if (!iod->nents)
-		goto out;
+		goto out_free_sg;
 
 	if (is_pci_p2pdma_page(sg_page(iod->sg)))
 		nr_mapped = pci_p2pdma_map_sg_attrs(dev->dev, iod->sg,
@@ -872,16 +875,21 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
 		nr_mapped = dma_map_sg_attrs(dev->dev, iod->sg, iod->nents,
 					     rq_dma_dir(req), DMA_ATTR_NO_WARN);
 	if (!nr_mapped)
-		goto out;
+		goto out_free_sg;
 
 	iod->use_sgl = nvme_pci_use_sgls(dev, req);
 	if (iod->use_sgl)
 		ret = nvme_pci_setup_sgls(dev, req, &cmnd->rw, nr_mapped);
 	else
 		ret = nvme_pci_setup_prps(dev, req, &cmnd->rw);
-out:
 	if (ret != BLK_STS_OK)
-		nvme_unmap_data(dev, req);
+		goto out_dma_unmap;
+	return BLK_STS_OK;
+
+out_dma_unmap:
+	nvme_unmap_sg(dev, req);
+out_free_sg:
+	mempool_free(iod->sg, dev->iod_mempool);
 	return ret;
 }
 
-- 
2.29.2



From mgurtovoy at nvidia.com  Wed Jan 20 05:02:58 2021
From: mgurtovoy at nvidia.com (Max Gurtovoy)
Date: Wed, 20 Jan 2021 12:02:58 +0200
Subject: [PATCH 1/1] nvme: update enumerations for status codes
In-Reply-To: <BYAPR04MB4965E1DC0180C2E5789E505186A20@BYAPR04MB4965.namprd04.prod.outlook.com>
References: <20210104125947.160984-1-mgurtovoy@nvidia.com>
 <BYAPR04MB4965E1DC0180C2E5789E505186A20@BYAPR04MB4965.namprd04.prod.outlook.com>
Message-ID: <55ebc8c7-5631-1f99-1384-80ca85c26b0d@nvidia.com>


On 1/20/2021 7:09 AM, Chaitanya Kulkarni wrote:
> Max,
> On 1/4/21 04:59, Max Gurtovoy wrote:
>> All the updates are mentioned in the ratified NVMe 1.4 spec.
>>
>> Signed-off-by: Max Gurtovoy <mgurtovoy at nvidia.com>
>> ---
> I'm not against keeping the header file up to date with the spec,
> but should we add the error status into the kernel code even if
> we are not using it in the host/target driver ?

I we go with this approach we should remove half of the code inside nvme.h


>
> Here we add 24 lines which we have not used at all.
>>   include/linux/nvme.h | 24 ++++++++++++++++++++----
>>   1 file changed, 20 insertions(+), 4 deletions(-)
>>
> Regarding the nvme-cli this is much needed a sync since it does
> decode all the errors if I'm not wrong.

I can sync it in V2.



From hch at lst.de  Wed Jan 20 05:07:38 2021
From: hch at lst.de (Christoph Hellwig)
Date: Wed, 20 Jan 2021 11:07:38 +0100
Subject: [PATCH v2 0/2] block: add zone write granularity limit
In-Reply-To: <20210119131723.1637853-1-damien.lemoal@wdc.com>
References: <20210119131723.1637853-1-damien.lemoal@wdc.com>
Message-ID: <20210120100738.GA25746@lst.de>

Shouldn't zonefs (in addition to the pending btrfs and nvmet patches)
start using this new value instead pf the physical block size?


From hch at lst.de  Wed Jan 20 05:10:18 2021
From: hch at lst.de (Christoph Hellwig)
Date: Wed, 20 Jan 2021 11:10:18 +0100
Subject: [PATCH v2 1/2] block: introduce zone_write_granularity limit
In-Reply-To: <20210119131723.1637853-2-damien.lemoal@wdc.com>
References: <20210119131723.1637853-1-damien.lemoal@wdc.com>
 <20210119131723.1637853-2-damien.lemoal@wdc.com>
Message-ID: <20210120101018.GB25746@lst.de>

On Tue, Jan 19, 2021 at 10:17:22PM +0900, Damien Le Moal wrote:
> Per ZBC and ZAC specifications, host-managed SMR hard-disks mandate that
> all writes into sequential write required zones be aligned to the device
> physical block size. However, NVMe ZNS does not have this constraint and
> allows write operations into sequential zones to be logical block size
> aligned. This inconsistency does not help with portability of software
> across device types.
> To solve this, introduce the zone_write_granularity queue limit to
> indicate the alignment constraint, in bytes, of write operations into
> zones of a zoned block device. This new limit is exported as a
> read-only sysfs queue attribute and the helper
> blk_queue_zone_write_granularity() introduced for drivers to set this
> limit. The scsi disk driver is modified to use this helper to set
> host-managed SMR disk zone write granularity to the disk physical block
> size. The nvme driver zns support use this helper to set the new limit
> to the logical block size of the zoned namespace.
> 
> Signed-off-by: Damien Le Moal <damien.lemoal at wdc.com>
> ---
>  Documentation/block/queue-sysfs.rst |  7 +++++++
>  block/blk-settings.c                | 28 ++++++++++++++++++++++++++++
>  block/blk-sysfs.c                   |  7 +++++++
>  drivers/nvme/host/zns.c             |  1 +
>  drivers/scsi/sd_zbc.c               | 10 ++++++++++
>  include/linux/blkdev.h              |  3 +++
>  6 files changed, 56 insertions(+)
> 
> diff --git a/Documentation/block/queue-sysfs.rst b/Documentation/block/queue-sysfs.rst
> index 2638d3446b79..c8bf8bc3c03a 100644
> --- a/Documentation/block/queue-sysfs.rst
> +++ b/Documentation/block/queue-sysfs.rst
> @@ -273,4 +273,11 @@ devices are described in the ZBC (Zoned Block Commands) and ZAC
>  do not support zone commands, they will be treated as regular block devices
>  and zoned will report "none".
>  
> +zone_write_granularity (RO)
> +---------------------------
> +This indicates the alignment constraint, in bytes, for write operations in
> +sequential zones of zoned block devices (devices with a zoned attributed
> +that reports "host-managed" or "host-aware"). This value is always 0 for
> +regular block devices.
> +
>  Jens Axboe <jens.axboe at oracle.com>, February 2009
> diff --git a/block/blk-settings.c b/block/blk-settings.c
> index 43990b1d148b..6be6ed9485e3 100644
> --- a/block/blk-settings.c
> +++ b/block/blk-settings.c
> @@ -60,6 +60,7 @@ void blk_set_default_limits(struct queue_limits *lim)
>  	lim->io_opt = 0;
>  	lim->misaligned = 0;
>  	lim->zoned = BLK_ZONED_NONE;
> +	lim->zone_write_granularity = 0;

I think this should default to 512 just like the logic and physical
block size.

>  }
>  EXPORT_SYMBOL(blk_set_default_limits);
>  
> @@ -366,6 +367,31 @@ void blk_queue_physical_block_size(struct request_queue *q, unsigned int size)
>  }
>  EXPORT_SYMBOL(blk_queue_physical_block_size);
>  
> +/**
> + * blk_queue_zone_write_granularity - set zone write granularity for the queue
> + * @q:  the request queue for the zoned device
> + * @size:  the zone write granularity size, in bytes
> + *
> + * Description:
> + *   This should be set to the lowest possible size allowing to write in
> + *   sequential zones of a zoned block device.
> + */
> +void blk_queue_zone_write_granularity(struct request_queue *q,
> +				      unsigned int size)
> +{
> +	if (WARN_ON(!blk_queue_is_zoned(q)))
> +		return;
> +
> +	q->limits.zone_write_granularity = size;
> +
> +	if (q->limits.zone_write_granularity < q->limits.logical_block_size)
> +		q->limits.zone_write_granularity = q->limits.logical_block_size;

I think this should be a WARN_ON_ONCE.

> +	if (q->limits.zone_write_granularity < q->limits.io_min)
> +		q->limits.zone_write_granularity = q->limits.io_min;

I don't think this makes sense at all.

> +static ssize_t queue_zone_write_granularity_show(struct request_queue *q, char *page)

Overly long line.

> +	/*
> +	 * Per ZBC and ZAC specifications, writes in sequential write required
> +	 * zones of host-managed devices must be aligned to the device physical
> +	 * block size.
> +	 */
> +	if (blk_queue_zoned_model(q) == BLK_ZONED_HM)
> +		blk_queue_zone_write_granularity(q, sdkp->physical_block_size);
> +	else
> +		blk_queue_zone_write_granularity(q, sdkp->device->sector_size);

Do we really want to special case HA drives here?  I though we generally
either treat them as drive managed (if they have partitions) or else like
host managed ones.


From hch at lst.de  Wed Jan 20 05:10:40 2021
From: hch at lst.de (Christoph Hellwig)
Date: Wed, 20 Jan 2021 11:10:40 +0100
Subject: [PATCH v2 2/2] block: document zone_append_max_bytes attribute
In-Reply-To: <20210119131723.1637853-3-damien.lemoal@wdc.com>
References: <20210119131723.1637853-1-damien.lemoal@wdc.com>
 <20210119131723.1637853-3-damien.lemoal@wdc.com>
Message-ID: <20210120101040.GC25746@lst.de>

Looks good,

Reviewed-by: Christoph Hellwig <hch at lst.de>


From Damien.LeMoal at wdc.com  Wed Jan 20 05:42:05 2021
From: Damien.LeMoal at wdc.com (Damien Le Moal)
Date: Wed, 20 Jan 2021 10:42:05 +0000
Subject: [PATCH v2 0/2] block: add zone write granularity limit
References: <20210119131723.1637853-1-damien.lemoal@wdc.com>
 <20210120100738.GA25746@lst.de>
Message-ID: <BL0PR04MB6514A8D408A7491BE9F1249DE7A20@BL0PR04MB6514.namprd04.prod.outlook.com>

On 2021/01/20 19:07, Christoph Hellwig wrote:
> Shouldn't zonefs (in addition to the pending btrfs and nvmet patches)
> start using this new value instead pf the physical block size?
> 

Yes for zonefs. I will add one patch to this series for that.
For nvmet patches, I will let Chaitanya handle that.
For on-going btrfs, I think we can cover that with btrfs-progs (check in mkfs)
for now and add a patch as a fix in 5.12 to check the FS block size on zoned
devices, if the series is accepted. Patching now would cause the btrfs tree to
not build.


-- 
Damien Le Moal
Western Digital Research


From Damien.LeMoal at wdc.com  Wed Jan 20 05:46:56 2021
From: Damien.LeMoal at wdc.com (Damien Le Moal)
Date: Wed, 20 Jan 2021 10:46:56 +0000
Subject: [PATCH v2 0/2] block: add zone write granularity limit
References: <20210119131723.1637853-1-damien.lemoal@wdc.com>
 <20210120100738.GA25746@lst.de>
Message-ID: <BL0PR04MB651400694A65F9FB395C5652E7A20@BL0PR04MB6514.namprd04.prod.outlook.com>

On 2021/01/20 19:07, Christoph Hellwig wrote:
> Shouldn't zonefs (in addition to the pending btrfs and nvmet patches)
> start using this new value instead pf the physical block size?
> 

And I think null_blk needs that limit set too. Forgot to add it.

-- 
Damien Le Moal
Western Digital Research


From Damien.LeMoal at wdc.com  Wed Jan 20 06:00:29 2021
From: Damien.LeMoal at wdc.com (Damien Le Moal)
Date: Wed, 20 Jan 2021 11:00:29 +0000
Subject: [PATCH v2 1/2] block: introduce zone_write_granularity limit
References: <20210119131723.1637853-1-damien.lemoal@wdc.com>
 <20210119131723.1637853-2-damien.lemoal@wdc.com>
 <20210120101018.GB25746@lst.de>
Message-ID: <BL0PR04MB65144D0B02939681617B61A8E7A20@BL0PR04MB6514.namprd04.prod.outlook.com>

On 2021/01/20 19:10, Christoph Hellwig wrote:
> On Tue, Jan 19, 2021 at 10:17:22PM +0900, Damien Le Moal wrote:
>> Per ZBC and ZAC specifications, host-managed SMR hard-disks mandate that
>> all writes into sequential write required zones be aligned to the device
>> physical block size. However, NVMe ZNS does not have this constraint and
>> allows write operations into sequential zones to be logical block size
>> aligned. This inconsistency does not help with portability of software
>> across device types.
>> To solve this, introduce the zone_write_granularity queue limit to
>> indicate the alignment constraint, in bytes, of write operations into
>> zones of a zoned block device. This new limit is exported as a
>> read-only sysfs queue attribute and the helper
>> blk_queue_zone_write_granularity() introduced for drivers to set this
>> limit. The scsi disk driver is modified to use this helper to set
>> host-managed SMR disk zone write granularity to the disk physical block
>> size. The nvme driver zns support use this helper to set the new limit
>> to the logical block size of the zoned namespace.
>>
>> Signed-off-by: Damien Le Moal <damien.lemoal at wdc.com>
>> ---
>>  Documentation/block/queue-sysfs.rst |  7 +++++++
>>  block/blk-settings.c                | 28 ++++++++++++++++++++++++++++
>>  block/blk-sysfs.c                   |  7 +++++++
>>  drivers/nvme/host/zns.c             |  1 +
>>  drivers/scsi/sd_zbc.c               | 10 ++++++++++
>>  include/linux/blkdev.h              |  3 +++
>>  6 files changed, 56 insertions(+)
>>
>> diff --git a/Documentation/block/queue-sysfs.rst b/Documentation/block/queue-sysfs.rst
>> index 2638d3446b79..c8bf8bc3c03a 100644
>> --- a/Documentation/block/queue-sysfs.rst
>> +++ b/Documentation/block/queue-sysfs.rst
>> @@ -273,4 +273,11 @@ devices are described in the ZBC (Zoned Block Commands) and ZAC
>>  do not support zone commands, they will be treated as regular block devices
>>  and zoned will report "none".
>>  
>> +zone_write_granularity (RO)
>> +---------------------------
>> +This indicates the alignment constraint, in bytes, for write operations in
>> +sequential zones of zoned block devices (devices with a zoned attributed
>> +that reports "host-managed" or "host-aware"). This value is always 0 for
>> +regular block devices.
>> +
>>  Jens Axboe <jens.axboe at oracle.com>, February 2009
>> diff --git a/block/blk-settings.c b/block/blk-settings.c
>> index 43990b1d148b..6be6ed9485e3 100644
>> --- a/block/blk-settings.c
>> +++ b/block/blk-settings.c
>> @@ -60,6 +60,7 @@ void blk_set_default_limits(struct queue_limits *lim)
>>  	lim->io_opt = 0;
>>  	lim->misaligned = 0;
>>  	lim->zoned = BLK_ZONED_NONE;
>> +	lim->zone_write_granularity = 0;
> 
> I think this should default to 512 just like the logic and physical
> block size.

Hmm. I wanted to keep this limit to 0 for regular devices. If we default to 512,
regular devices will see that value. They can ignore it of course, but having it
as 0 makes it clear that it should be ignored.

> 
>>  }
>>  EXPORT_SYMBOL(blk_set_default_limits);
>>  
>> @@ -366,6 +367,31 @@ void blk_queue_physical_block_size(struct request_queue *q, unsigned int size)
>>  }
>>  EXPORT_SYMBOL(blk_queue_physical_block_size);
>>  
>> +/**
>> + * blk_queue_zone_write_granularity - set zone write granularity for the queue
>> + * @q:  the request queue for the zoned device
>> + * @size:  the zone write granularity size, in bytes
>> + *
>> + * Description:
>> + *   This should be set to the lowest possible size allowing to write in
>> + *   sequential zones of a zoned block device.
>> + */
>> +void blk_queue_zone_write_granularity(struct request_queue *q,
>> +				      unsigned int size)
>> +{
>> +	if (WARN_ON(!blk_queue_is_zoned(q)))
>> +		return;
>> +
>> +	q->limits.zone_write_granularity = size;
>> +
>> +	if (q->limits.zone_write_granularity < q->limits.logical_block_size)
>> +		q->limits.zone_write_granularity = q->limits.logical_block_size;
> 
> I think this should be a WARN_ON_ONCE.

OK.

> 
>> +	if (q->limits.zone_write_granularity < q->limits.io_min)
>> +		q->limits.zone_write_granularity = q->limits.io_min;
> 
> I don't think this makes sense at all.

Arg ! Yes, that is a hint only ! I misread the comments for blk_limits_io_min().
Will remove this.

> 
>> +static ssize_t queue_zone_write_granularity_show(struct request_queue *q, char *page)
> 
> Overly long line.
> 
>> +	/*
>> +	 * Per ZBC and ZAC specifications, writes in sequential write required
>> +	 * zones of host-managed devices must be aligned to the device physical
>> +	 * block size.
>> +	 */
>> +	if (blk_queue_zoned_model(q) == BLK_ZONED_HM)
>> +		blk_queue_zone_write_granularity(q, sdkp->physical_block_size);
>> +	else
>> +		blk_queue_zone_write_granularity(q, sdkp->device->sector_size);
> 
> Do we really want to special case HA drives here?  I though we generally
> either treat them as drive managed (if they have partitions) or else like
> host managed ones.

If the HA drive is treated as drive-managed (i.e. it has a partition), then the
model here will be seen as BLK_ZONED_NONE and we should ignore it, or better,
set the zone_write_granularity to 0. If the drive is actually used as a zoned
drive, then we will see BLK_ZONED_HA here and we can use the logical block size
since HA drives do not have that restriction on physical block alignment.
So my code above is wrong. The else should be

else if (blk_queue_zoned_model(q) == BLK_ZONED_HA)

And I think we also need to add "q->limit.zone_write_granularity = 0" in
blk_queue_set_zoned() if model == BLK_ZONED_NONE at the end of that function.

Will send a v3 with these fixes.


-- 
Damien Le Moal
Western Digital Research


From hch at lst.de  Wed Jan 20 07:36:49 2021
From: hch at lst.de (Christoph Hellwig)
Date: Wed, 20 Jan 2021 13:36:49 +0100
Subject: [PATCH v2 1/2] block: introduce zone_write_granularity limit
In-Reply-To: <BL0PR04MB65144D0B02939681617B61A8E7A20@BL0PR04MB6514.namprd04.prod.outlook.com>
References: <20210119131723.1637853-1-damien.lemoal@wdc.com>
 <20210119131723.1637853-2-damien.lemoal@wdc.com>
 <20210120101018.GB25746@lst.de>
 <BL0PR04MB65144D0B02939681617B61A8E7A20@BL0PR04MB6514.namprd04.prod.outlook.com>
Message-ID: <20210120123649.GA3870@lst.de>

On Wed, Jan 20, 2021 at 11:00:29AM +0000, Damien Le Moal wrote:
> Hmm. I wanted to keep this limit to 0 for regular devices. If we default to 512,
> regular devices will see that value. They can ignore it of course, but having it
> as 0 makes it clear that it should be ignored.

Hmm.  Maybe we should keep the 0 default and only set it in sd.c.  Then the
query helper can default to the logical block size instead.  That'll just d
o the right thing without changes to most drivers.


From marcorr at google.com  Wed Jan 20 10:19:34 2021
From: marcorr at google.com (Marc Orr)
Date: Wed, 20 Jan 2021 07:19:34 -0800
Subject: [PATCH 1/2] nvme-pci: refactor nvme_unmap_data
In-Reply-To: <20210120094915.3198346-2-hch@lst.de>
References: <20210120094915.3198346-1-hch@lst.de>
 <20210120094915.3198346-2-hch@lst.de>
Message-ID: <CAA03e5FYn0Z2gQhOBVRCyffeNs8iQ=2ZUVgZbig5b6xe60iE4g@mail.gmail.com>

On Wed, Jan 20, 2021 at 1:49 AM Christoph Hellwig <hch at lst.de> wrote:
>
> Split out three helpers from nvme_unmap_data that will allow finer grained
> unwinding from nvme_map_data.
>
> Signed-off-by: Christoph Hellwig <hch at lst.de>
> ---
>  drivers/nvme/host/pci.c | 77 ++++++++++++++++++++++++++---------------
>  1 file changed, 49 insertions(+), 28 deletions(-)
>
> diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
> index 25456d02eddb8c..e29ece9e4d4b8e 100644
> --- a/drivers/nvme/host/pci.c
> +++ b/drivers/nvme/host/pci.c
> @@ -543,50 +543,71 @@ static inline bool nvme_pci_use_sgls(struct nvme_dev *dev, struct request *req)
>         return true;
>  }
>
> -static void nvme_unmap_data(struct nvme_dev *dev, struct request *req)
> +static void nvme_free_prps(struct nvme_dev *dev, struct request *req)
>  {
> -       struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
>         const int last_prp = NVME_CTRL_PAGE_SIZE / sizeof(__le64) - 1;
> -       dma_addr_t dma_addr = iod->first_dma, next_dma_addr;
> +       struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
> +       dma_addr_t dma_addr = iod->first_dma;
>         int i;
>
> -       if (iod->dma_len) {
> -               dma_unmap_page(dev->dev, dma_addr, iod->dma_len,
> -                              rq_dma_dir(req));
> -               return;
> +       for (i = 0; i < iod->npages; i++) {
> +               __le64 *prp_list = nvme_pci_iod_list(req)[i];
> +               dma_addr_t next_dma_addr = le64_to_cpu(prp_list[last_prp]);
> +
> +               dma_pool_free(dev->prp_page_pool, prp_list, dma_addr);
> +               dma_addr = next_dma_addr;
>         }
>
> -       WARN_ON_ONCE(!iod->nents);
> +}
>
> -       if (is_pci_p2pdma_page(sg_page(iod->sg)))
> -               pci_p2pdma_unmap_sg(dev->dev, iod->sg, iod->nents,
> -                                   rq_dma_dir(req));
> -       else
> -               dma_unmap_sg(dev->dev, iod->sg, iod->nents, rq_dma_dir(req));
> +static void nvme_free_sgls(struct nvme_dev *dev, struct request *req)
> +{
> +       const int last_sg = SGES_PER_PAGE - 1;
> +       struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
> +       dma_addr_t dma_addr = iod->first_dma;
> +       int i;
>
> +       for (i = 0; i < iod->npages; i++) {
> +               struct nvme_sgl_desc *sg_list = nvme_pci_iod_list(req)[i];
> +               dma_addr_t next_dma_addr = le64_to_cpu((sg_list[last_sg]).addr);
>
> -       if (iod->npages == 0)
> -               dma_pool_free(dev->prp_small_pool, nvme_pci_iod_list(req)[0],
> -                       dma_addr);
> +               dma_pool_free(dev->prp_page_pool, sg_list, dma_addr);
> +               dma_addr = next_dma_addr;
> +       }
>
> -       for (i = 0; i < iod->npages; i++) {
> -               void *addr = nvme_pci_iod_list(req)[i];
> +}
>
> -               if (iod->use_sgl) {
> -                       struct nvme_sgl_desc *sg_list = addr;
> +static void nvme_unmap_sg(struct nvme_dev *dev, struct request *req)
> +{
> +       struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
>
> -                       next_dma_addr =
> -                           le64_to_cpu((sg_list[SGES_PER_PAGE - 1]).addr);
> -               } else {
> -                       __le64 *prp_list = addr;
> +       if (is_pci_p2pdma_page(sg_page(iod->sg)))
> +               pci_p2pdma_unmap_sg(dev->dev, iod->sg, iod->nents,
> +                                   rq_dma_dir(req));
> +       else
> +               dma_unmap_sg(dev->dev, iod->sg, iod->nents, rq_dma_dir(req));
> +}
>
> -                       next_dma_addr = le64_to_cpu(prp_list[last_prp]);
> -               }
> +static void nvme_unmap_data(struct nvme_dev *dev, struct request *req)
> +{
> +       struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
>
> -               dma_pool_free(dev->prp_page_pool, addr, dma_addr);
> -               dma_addr = next_dma_addr;
> +       if (iod->dma_len) {
> +               dma_unmap_page(dev->dev, iod->first_dma, iod->dma_len,
> +                              rq_dma_dir(req));
> +               return;
>         }
>
> +       WARN_ON_ONCE(!iod->nents);
> +
> +       nvme_unmap_sg(dev, req);
> +       if (iod->npages == 0)
> +               dma_pool_free(dev->prp_small_pool, nvme_pci_iod_list(req)[0],
> +                             iod->first_dma);
> +       else if (iod->use_sgl)
> +               nvme_free_sgls(dev, req);
> +       else
> +               nvme_free_prps(dev, req);
>         mempool_free(iod->sg, dev->iod_mempool);
>  }

Reviewed-by: Marc Orr <marcorr at google.com>

>
> --
> 2.29.2
>


From marcorr at google.com  Wed Jan 20 10:23:39 2021
From: marcorr at google.com (Marc Orr)
Date: Wed, 20 Jan 2021 07:23:39 -0800
Subject: [PATCH 2/2] nvme-pci: fix error unwind in nvme_map_data
In-Reply-To: <20210120094915.3198346-3-hch@lst.de>
References: <20210120094915.3198346-1-hch@lst.de>
 <20210120094915.3198346-3-hch@lst.de>
Message-ID: <CAA03e5Hb49rpNq2A8hmvo6tVrLnon0yAUiZvWvd8THCXyDQ-kg@mail.gmail.com>

On Wed, Jan 20, 2021 at 1:49 AM Christoph Hellwig <hch at lst.de> wrote:
>
> Properly unwind step by step using refactored helpers from nvme_unmap_data
> to avoid a potential double dma_unmap on a mapping failure.
>
> Reported-by: Marc Orr <marcorr at google.com>
> Signed-off-by: Christoph Hellwig <hch at lst.de>

Should these patches go to stable?

> ---
>  drivers/nvme/host/pci.c | 28 ++++++++++++++++++----------
>  1 file changed, 18 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
> index e29ece9e4d4b8e..4e93d1b52df202 100644
> --- a/drivers/nvme/host/pci.c
> +++ b/drivers/nvme/host/pci.c
> @@ -683,7 +683,7 @@ static blk_status_t nvme_pci_setup_prps(struct nvme_dev *dev,
>                         __le64 *old_prp_list = prp_list;
>                         prp_list = dma_pool_alloc(pool, GFP_ATOMIC, &prp_dma);
>                         if (!prp_list)
> -                               return BLK_STS_RESOURCE;
> +                               goto free_prps;
>                         list[iod->npages++] = prp_list;
>                         prp_list[0] = old_prp_list[i - 1];
>                         old_prp_list[i - 1] = cpu_to_le64(prp_dma);
> @@ -703,14 +703,14 @@ static blk_status_t nvme_pci_setup_prps(struct nvme_dev *dev,
>                 dma_addr = sg_dma_address(sg);
>                 dma_len = sg_dma_len(sg);
>         }
> -
>  done:
>         cmnd->dptr.prp1 = cpu_to_le64(sg_dma_address(iod->sg));
>         cmnd->dptr.prp2 = cpu_to_le64(iod->first_dma);
> -
>         return BLK_STS_OK;
> -
> - bad_sgl:
> +free_prps:
> +       nvme_free_prps(dev, req);
> +       return BLK_STS_RESOURCE;
> +bad_sgl:
>         WARN(DO_ONCE(nvme_print_sgl, iod->sg, iod->nents),
>                         "Invalid SGL for payload:%d nents:%d\n",
>                         blk_rq_payload_bytes(req), iod->nents);
> @@ -782,7 +782,7 @@ static blk_status_t nvme_pci_setup_sgls(struct nvme_dev *dev,
>
>                         sg_list = dma_pool_alloc(pool, GFP_ATOMIC, &sgl_dma);
>                         if (!sg_list)
> -                               return BLK_STS_RESOURCE;
> +                               goto free_sgls;
>
>                         i = 0;
>                         nvme_pci_iod_list(req)[iod->npages++] = sg_list;
> @@ -795,6 +795,9 @@ static blk_status_t nvme_pci_setup_sgls(struct nvme_dev *dev,
>         } while (--entries > 0);
>
>         return BLK_STS_OK;
> +free_sgls:
> +       nvme_free_sgls(dev, req);
> +       return BLK_STS_RESOURCE;
>  }
>
>  static blk_status_t nvme_setup_prp_simple(struct nvme_dev *dev,
> @@ -863,7 +866,7 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
>         sg_init_table(iod->sg, blk_rq_nr_phys_segments(req));
>         iod->nents = blk_rq_map_sg(req->q, req, iod->sg);
>         if (!iod->nents)
> -               goto out;
> +               goto out_free_sg;
>
>         if (is_pci_p2pdma_page(sg_page(iod->sg)))
>                 nr_mapped = pci_p2pdma_map_sg_attrs(dev->dev, iod->sg,
> @@ -872,16 +875,21 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
>                 nr_mapped = dma_map_sg_attrs(dev->dev, iod->sg, iod->nents,
>                                              rq_dma_dir(req), DMA_ATTR_NO_WARN);
>         if (!nr_mapped)
> -               goto out;
> +               goto out_free_sg;
>
>         iod->use_sgl = nvme_pci_use_sgls(dev, req);
>         if (iod->use_sgl)
>                 ret = nvme_pci_setup_sgls(dev, req, &cmnd->rw, nr_mapped);
>         else
>                 ret = nvme_pci_setup_prps(dev, req, &cmnd->rw);
> -out:
>         if (ret != BLK_STS_OK)
> -               nvme_unmap_data(dev, req);
> +               goto out_dma_unmap;
> +       return BLK_STS_OK;
> +
> +out_dma_unmap:

nit: Naming this label out_sg_unmap or out_unmap_sg might be a little
more clear, since the line below doesn't have the word dma anywhere.

> +       nvme_unmap_sg(dev, req);
> +out_free_sg:
> +       mempool_free(iod->sg, dev->iod_mempool);
>         return ret;
>  }

Reviewed-by: Marc Orr <marcorr at google.com>

>
> --
> 2.29.2
>


From hch at lst.de  Wed Jan 20 11:48:24 2021
From: hch at lst.de (Christoph Hellwig)
Date: Wed, 20 Jan 2021 17:48:24 +0100
Subject: [PATCH 2/2] nvme-pci: fix error unwind in nvme_map_data
In-Reply-To: <CAA03e5Hb49rpNq2A8hmvo6tVrLnon0yAUiZvWvd8THCXyDQ-kg@mail.gmail.com>
References: <20210120094915.3198346-1-hch@lst.de>
 <20210120094915.3198346-3-hch@lst.de>
 <CAA03e5Hb49rpNq2A8hmvo6tVrLnon0yAUiZvWvd8THCXyDQ-kg@mail.gmail.com>
Message-ID: <20210120164824.GA21874@lst.de>

On Wed, Jan 20, 2021 at 07:23:39AM -0800, Marc Orr wrote:
> On Wed, Jan 20, 2021 at 1:49 AM Christoph Hellwig <hch at lst.de> wrote:
> >
> > Properly unwind step by step using refactored helpers from nvme_unmap_data
> > to avoid a potential double dma_unmap on a mapping failure.
> >
> > Reported-by: Marc Orr <marcorr at google.com>
> > Signed-off-by: Christoph Hellwig <hch at lst.de>
> 
> Should these patches go to stable?

Yes.  I've added the proper fixes tag:

Fixes: 7fe07d14f71f ("nvme-pci: merge nvme_free_iod into nvme_unmap_data")


From kbusch at kernel.org  Wed Jan 20 12:42:52 2021
From: kbusch at kernel.org (Keith Busch)
Date: Thu, 21 Jan 2021 02:42:52 +0900
Subject: [PATCH 2/2] nvme-pci: fix error unwind in nvme_map_data
In-Reply-To: <20210120164824.GA21874@lst.de>
References: <20210120094915.3198346-1-hch@lst.de>
 <20210120094915.3198346-3-hch@lst.de>
 <CAA03e5Hb49rpNq2A8hmvo6tVrLnon0yAUiZvWvd8THCXyDQ-kg@mail.gmail.com>
 <20210120164824.GA21874@lst.de>
Message-ID: <20210120174252.GA27657@redsun51.ssa.fujisawa.hgst.com>

On Wed, Jan 20, 2021 at 05:48:24PM +0100, Christoph Hellwig wrote:
> On Wed, Jan 20, 2021 at 07:23:39AM -0800, Marc Orr wrote:
> > On Wed, Jan 20, 2021 at 1:49 AM Christoph Hellwig <hch at lst.de> wrote:
> > >
> > > Properly unwind step by step using refactored helpers from nvme_unmap_data
> > > to avoid a potential double dma_unmap on a mapping failure.
> > >
> > > Reported-by: Marc Orr <marcorr at google.com>
> > > Signed-off-by: Christoph Hellwig <hch at lst.de>
> > 
> > Should these patches go to stable?
> 
> Yes.  I've added the proper fixes tag:
> 
> Fixes: 7fe07d14f71f ("nvme-pci: merge nvme_free_iod into nvme_unmap_data")

Patches look good.

Reviewed-by: Keith Busch <kbusch at kernel.org>

Just fyi, the 2/2 is the only one with the "Fixes" tag, but it depends
on 1/2 to compile. It applies cleanly to the recent stables, though, so
stable bot might have some trouble with it.


From hch at lst.de  Wed Jan 20 12:56:20 2021
From: hch at lst.de (Christoph Hellwig)
Date: Wed, 20 Jan 2021 18:56:20 +0100
Subject: [PATCH 2/2] nvme-pci: fix error unwind in nvme_map_data
In-Reply-To: <20210120174252.GA27657@redsun51.ssa.fujisawa.hgst.com>
References: <20210120094915.3198346-1-hch@lst.de>
 <20210120094915.3198346-3-hch@lst.de>
 <CAA03e5Hb49rpNq2A8hmvo6tVrLnon0yAUiZvWvd8THCXyDQ-kg@mail.gmail.com>
 <20210120164824.GA21874@lst.de>
 <20210120174252.GA27657@redsun51.ssa.fujisawa.hgst.com>
Message-ID: <20210120175620.GA26100@lst.de>

On Thu, Jan 21, 2021 at 02:42:52AM +0900, Keith Busch wrote:
> On Wed, Jan 20, 2021 at 05:48:24PM +0100, Christoph Hellwig wrote:
> > On Wed, Jan 20, 2021 at 07:23:39AM -0800, Marc Orr wrote:
> > > On Wed, Jan 20, 2021 at 1:49 AM Christoph Hellwig <hch at lst.de> wrote:
> > > >
> > > > Properly unwind step by step using refactored helpers from nvme_unmap_data
> > > > to avoid a potential double dma_unmap on a mapping failure.
> > > >
> > > > Reported-by: Marc Orr <marcorr at google.com>
> > > > Signed-off-by: Christoph Hellwig <hch at lst.de>
> > > 
> > > Should these patches go to stable?
> > 
> > Yes.  I've added the proper fixes tag:
> > 
> > Fixes: 7fe07d14f71f ("nvme-pci: merge nvme_free_iod into nvme_unmap_data")
> 
> Patches look good.
> 
> Reviewed-by: Keith Busch <kbusch at kernel.org>
> 
> Just fyi, the 2/2 is the only one with the "Fixes" tag, but it depends
> on 1/2 to compile. It applies cleanly to the recent stables, though, so
> stable bot might have some trouble with it.

patch 2 obviously depends on 1, the bot has been pretty good at
figuring that out.


From sagi at grimberg.me  Wed Jan 20 16:35:47 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 20 Jan 2021 13:35:47 -0800
Subject: [PATCH v2 4/6] nvme-rdma: avoid IO error and repeated request
 completion
In-Reply-To: <0b5c8e31-8dc2-994a-1710-1b1be07549c9@huawei.com>
References: <20210107033149.15701-1-lengchao@huawei.com>
 <20210107033149.15701-5-lengchao@huawei.com>
 <07e41b4f-914a-11e8-5638-e2d6408feb3f@grimberg.me>
 <7b12be41-0fcd-5a22-0e01-8cd4ac9cde5b@huawei.com>
 <a3404c7d-ccc8-0d55-d4a8-fc15107c90e6@grimberg.me>
 <695b6839-5333-c342-2189-d7aaeba797a7@huawei.com>
 <4ff22d33-12fa-1f70-3606-54821f314c45@grimberg.me>
 <0b5c8e31-8dc2-994a-1710-1b1be07549c9@huawei.com>
Message-ID: <2ed5391c-fe43-f512-adf0-214effd5d599@grimberg.me>


is not something we should be handling in nvme. block drivers
>>>> should be able to fail queue_rq, and this all should live in the
>>>> block layer.
>>> Of course, it is also an idea to repair the block drivers directly.
>>> However, block layer is unaware of nvme native multipathing,
>>
>> Nor it should be
>>
>>> will cause the request return error which should be avoided.
>>
>> Not sure I understand..
>> requests should failover for path related errors,
>> what queue_rq errors are expected to be failed over from your
>> perspective?
> Although fail over for only path related errors is the best choice, it's
> almost impossible to achieve.
> The probability of non-path-related errors is very low. Although these
> errors do not require fail over retry, the cost of fail over retry
> is complete the request with error delay a bit long time(retry several
> times). It's not the best choice, but I think it's acceptable, because
> HBA driver does not have path-related error codes but only general error
> codes. It is difficult to identify whether the general error codes are
> path-related.

If we have a SW bug or breakage that can happen occasionally, this can
result in a constant failover rather than a simple failure. This is just
not a good approach IMO.

>>> The scenario: use two HBAs for nvme native multipath, and then one HBA
>>> fault,
>>
>> What is the specific error the driver sees?
> The path related error code is closely related to HBA driver
> implementation. In general it is EIO. I don't think it's a good idea to
> assume what general error code the driver returns in the event of a path
> error.

But assuming every error is a path error a good idea?

>>> the blk_status_t of queue_rq is BLK_STS_IOERR, blk-mq will call
>>> blk_mq_end_request to complete the request which bypass name native
>>> multipath. We expect the request fail over to normal HBA, but the 
>>> request
>>> is directly completed with BLK_STS_IOERR.
>>> The two scenarios can be fixed by directly completing the request in 
>>> queue_rq.
>> Well, certainly this one-shot always return 0 and complete the command
>> with HOST_PATH error is not a good approach IMO
> So what's the better option? Just complete the request with host path
> error for non-ENOMEM and EAGAIN returned by the HBA driver?

Well, the correct thing to do here would be to clone the bio and
failover if the end_io error status is BLK_STS_IOERR. That sucks
because it adds overhead, but this proposal doesn't sit well. it
looks wrong to me.

Alternatively, a more creative idea would be to encode the error
status somehow in the cookie returned from submit_bio, but that
also feels like a small(er) hack..


From lengchao at huawei.com  Wed Jan 20 20:34:30 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 21 Jan 2021 09:34:30 +0800
Subject: [PATCH v2 4/6] nvme-rdma: avoid IO error and repeated request
 completion
In-Reply-To: <2ed5391c-fe43-f512-adf0-214effd5d599@grimberg.me>
References: <20210107033149.15701-1-lengchao@huawei.com>
 <20210107033149.15701-5-lengchao@huawei.com>
 <07e41b4f-914a-11e8-5638-e2d6408feb3f@grimberg.me>
 <7b12be41-0fcd-5a22-0e01-8cd4ac9cde5b@huawei.com>
 <a3404c7d-ccc8-0d55-d4a8-fc15107c90e6@grimberg.me>
 <695b6839-5333-c342-2189-d7aaeba797a7@huawei.com>
 <4ff22d33-12fa-1f70-3606-54821f314c45@grimberg.me>
 <0b5c8e31-8dc2-994a-1710-1b1be07549c9@huawei.com>
 <2ed5391c-fe43-f512-adf0-214effd5d599@grimberg.me>
Message-ID: <6bfca033-8fda-4ace-c05f-285fccb070fd@huawei.com>



On 2021/1/21 5:35, Sagi Grimberg wrote:
> 
> is not something we should be handling in nvme. block drivers
>>>>> should be able to fail queue_rq, and this all should live in the
>>>>> block layer.
>>>> Of course, it is also an idea to repair the block drivers directly.
>>>> However, block layer is unaware of nvme native multipathing,
>>>
>>> Nor it should be
>>>
>>>> will cause the request return error which should be avoided.
>>>
>>> Not sure I understand..
>>> requests should failover for path related errors,
>>> what queue_rq errors are expected to be failed over from your
>>> perspective?
>> Although fail over for only path related errors is the best choice, it's
>> almost impossible to achieve.
>> The probability of non-path-related errors is very low. Although these
>> errors do not require fail over retry, the cost of fail over retry
>> is complete the request with error delay a bit long time(retry several
>> times). It's not the best choice, but I think it's acceptable, because
>> HBA driver does not have path-related error codes but only general error
>> codes. It is difficult to identify whether the general error codes are
>> path-related.
> 
> If we have a SW bug or breakage that can happen occasionally, this can
> result in a constant failover rather than a simple failure. This is just
> not a good approach IMO.
> 
>>>> The scenario: use two HBAs for nvme native multipath, and then one HBA
>>>> fault,
>>>
>>> What is the specific error the driver sees?
>> The path related error code is closely related to HBA driver
>> implementation. In general it is EIO. I don't think it's a good idea to
>> assume what general error code the driver returns in the event of a path
>> error.
> 
> But assuming every error is a path error a good idea?
Of course not, according to the old code logic, assuming !ENOMEM && !EAGIAN
for HBA drivers is a path error. I think it might be reasonable.
> 
>>>> the blk_status_t of queue_rq is BLK_STS_IOERR, blk-mq will call
>>>> blk_mq_end_request to complete the request which bypass name native
>>>> multipath. We expect the request fail over to normal HBA, but the request
>>>> is directly completed with BLK_STS_IOERR.
>>>> The two scenarios can be fixed by directly completing the request in queue_rq.
>>> Well, certainly this one-shot always return 0 and complete the command
>>> with HOST_PATH error is not a good approach IMO
>> So what's the better option? Just complete the request with host path
>> error for non-ENOMEM and EAGAIN returned by the HBA driver?
> 
> Well, the correct thing to do here would be to clone the bio and
> failover if the end_io error status is BLK_STS_IOERR. That sucks
> because it adds overhead, but this proposal doesn't sit well. it
> looks wrong to me.
> 
> Alternatively, a more creative idea would be to encode the error
> status somehow in the cookie returned from submit_bio, but that
> also feels like a small(er) hack.
If HBA drivers return !ENOMEM && !EAGIAN, queue_rq Directly call
nvme_complete_rq with NVME_SC_HOST_PATH_ERROR like
nvmf_fail_nonready_command. nvme_complete_rq will decide to retry,
fail over or end the request. This may not be the best, but there seems
to be no better choice.
I will try to send the patch v2.


From chapman6235 at comcast.net  Wed Jan 20 21:33:08 2021
From: chapman6235 at comcast.net (Bradley Chapman)
Date: Wed, 20 Jan 2021 21:33:08 -0500
Subject: Problem with SPCC 256GB NVMe 1.3 drive - refcount_t: underflow;
 use-after-free.
In-Reply-To: <BYAPR04MB496542BEF594F0380F7D41CF86A20@BYAPR04MB4965.namprd04.prod.outlook.com>
References: <f50bc59c-db11-bb44-55be-7b9db1119872@comcast.net>
 <BYAPR04MB49659C0F0F0E11D166B31E0586A40@BYAPR04MB4965.namprd04.prod.outlook.com>
 <a4c75497-d170-1e0f-8608-282231ff3a8e@comcast.net>
 <BYAPR04MB496542BEF594F0380F7D41CF86A20@BYAPR04MB4965.namprd04.prod.outlook.com>
Message-ID: <df46d7ce-ce70-1f43-0efd-7153761bcff0@comcast.net>

Good evening!

On 1/19/21 10:08 PM, Chaitanya Kulkarni wrote:
> On 1/18/21 10:33 AM, Bradley Chapman wrote:
>> Good afternoon!
>>
>> On 1/17/21 11:36 PM, Chaitanya Kulkarni wrote:
>>> On 1/17/21 11:05 AM, Bradley Chapman wrote:
>>>> [ 2836.554298] nvme nvme1: I/O 415 QID 3 timeout, disable controller
>>>> [ 2836.672064] blk_update_request: I/O error, dev nvme1n1, sector 16350
>>>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>>>> [ 2836.672072] blk_update_request: I/O error, dev nvme1n1, sector 16093
>>>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>>>> [ 2836.672074] blk_update_request: I/O error, dev nvme1n1, sector 15836
>>>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>>>> [ 2836.672076] blk_update_request: I/O error, dev nvme1n1, sector 15579
>>>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>>>> [ 2836.672078] blk_update_request: I/O error, dev nvme1n1, sector 15322
>>>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>>>> [ 2836.672080] blk_update_request: I/O error, dev nvme1n1, sector 15065
>>>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>>>> [ 2836.672082] blk_update_request: I/O error, dev nvme1n1, sector 14808
>>>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>>>> [ 2836.672083] blk_update_request: I/O error, dev nvme1n1, sector 14551
>>>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>>>> [ 2836.672085] blk_update_request: I/O error, dev nvme1n1, sector 14294
>>>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>>>> [ 2836.672087] blk_update_request: I/O error, dev nvme1n1, sector 14037
>>>> op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
>>>> [ 2836.672121] nvme nvme1: failed to mark controller live state
>>>> [ 2836.672123] nvme nvme1: Removing after probe failure status: -19
>>>> [ 2836.689016] Aborting journal on device dm-0-8.
>>>> [ 2836.689024] Buffer I/O error on dev dm-0, logical block 25198592,
>>>> lost sync page write
>>>> [ 2836.689027] JBD2: Error -5 detected when updating journal superblock
>>>> for dm-0-8.
>>> Without the knowledge of fs mount/format command I can only suspect that
>>> super
>>> block zeroing issued with write-zeroes request is translated into
>>> REQ_OP_WRITE_ZEROES which controller is not able to process resulting in
>>> the error. This analysis maybe wrong.
>>>
>>> Can you please share following details :-
>>>
>>> nvme id-ns /dev/nvme0n1 -H (we are interested in oncs part here)
>> I ran the requested command against /dev/nvme1n1 (since /dev/nvme0n1
>> works perfectly so far) and here is the result:
> Sorry my bad it suppose to be nvme id-ctrl /dev/nvme0n1 -H

$ nvme id-ctrl /dev/nvme1n1 -H

NVME Identify Controller:
vid       : 0x2263
ssvid     : 0x1d97
sn        : P2002287000000001296
mn        : SPCC M.2 PCIe SSD
fr        : V1.0
rab       : 6
ieee      : 000000
cmic      : 0
   [3:3] : 0     ANA not supported
   [2:2] : 0     PCI
   [1:1] : 0     Single Controller
   [0:0] : 0     Single Port

mdts      : 5
cntlid    : 1
ver       : 10300
rtd3r     : 249f0
rtd3e     : 13880
oaes      : 0x200
   [9:9] : 0x1   Firmware Activation Notices Supported
   [8:8] : 0     Namespace Attribute Changed Event Not Supported

ctratt    : 0
   [5:5] : 0     Predictable Latency Mode Not Supported
   [4:4] : 0     Endurance Groups Not Supported
   [3:3] : 0     Read Recovery Levels Not Supported
   [2:2] : 0     NVM Sets Not Supported
   [1:1] : 0     Non-Operational Power State Permissive Not Supported
   [0:0] : 0     128-bit Host Identifier Not Supported

rrls      : 0
oacs      : 0x7
   [8:8] : 0     Doorbell Buffer Config Not Supported
   [7:7] : 0     Virtualization Management Not Supported
   [6:6] : 0     NVMe-MI Send and Receive Not Supported
   [5:5] : 0     Directives Not Supported
   [4:4] : 0     Device Self-test Not Supported
   [3:3] : 0     NS Management and Attachment Not Supported
   [2:2] : 0x1   FW Commit and Download Supported
   [1:1] : 0x1   Format NVM Supported
   [0:0] : 0x1   Security Send and Receive Supported

acl       : 3
aerl      : 3
frmw      : 0x2
   [4:4] : 0     Firmware Activate Without Reset Not Supported
   [3:1] : 0x1   Number of Firmware Slots
   [0:0] : 0     Firmware Slot 1 Read/Write

lpa       : 0xa
   [3:3] : 0x1   Telemetry host/controller initiated log page Suporrted
   [2:2] : 0     Extended data for Get Log Page Not Supported
   [1:1] : 0x1   Command Effects Log Page Supported
   [0:0] : 0     SMART/Health Log Page per NS Not Supported

elpe      : 63
npss      : 0
avscc     : 0x1
   [0:0] : 0x1   Admin Vendor Specific Commands uses NVMe Format

apsta     : 0
   [0:0] : 0     Autonomous Power State Transitions Not Supported

wctemp    : 354
cctemp    : 363
mtfa      : 0
hmpre     : 16384
hmmin     : 16384
tnvmcap   : 0
unvmcap   : 0
rpmbs     : 0
  [31:24]: 0     Access Size
  [23:16]: 0     Total Size
   [5:3] : 0     Authentication Method
   [2:0] : 0     Number of RPMB Units

edstt     : 5
dsto      : 1
fwug      : 0
kas       : 0
hctma     : 0
   [0:0] : 0     Host Controlled Thermal Management Not Supported

mntmt     : 0
mxtmt     : 0
sanicap   : 0
   [2:2] : 0     Overwrite Sanitize Operation Not Supported
   [1:1] : 0     Block Erase Sanitize Operation Not Supported
   [0:0] : 0     Crypto Erase Sanitize Operation Not Supported

hmminds   : 0
hmmaxd    : 0
nsetidmax : 0
anatt     : 0
anacap    : 0
   [7:7] : 0     Non-zero group ID Not Supported
   [6:6] : 0     Group ID does not change
   [4:4] : 0     ANA Change state Not Supported
   [3:3] : 0     ANA Persistent Loss state Not Supported
   [2:2] : 0     ANA Inaccessible state Not Supported
   [1:1] : 0     ANA Non-optimized state Not Supported
   [0:0] : 0     ANA Optimized state Not Supported

anagrpmax : 0
nanagrpid : 0
sqes      : 0x66
   [7:4] : 0x6   Max SQ Entry Size (64)
   [3:0] : 0x6   Min SQ Entry Size (64)

cqes      : 0x44
   [7:4] : 0x4   Max CQ Entry Size (16)
   [3:0] : 0x4   Min CQ Entry Size (16)

maxcmd    : 0
nn        : 1
oncs      : 0x1d
   [6:6] : 0     Timestamp Not Supported
   [5:5] : 0     Reservations Not Supported
   [4:4] : 0x1   Save and Select Supported
   [3:3] : 0x1   Write Zeroes Supported
   [2:2] : 0x1   Data Set Management Supported
   [1:1] : 0     Write Uncorrectable Not Supported
   [0:0] : 0x1   Compare Supported

fuses     : 0
   [0:0] : 0     Fused Compare and Write Not Supported

fna       : 0x3
   [2:2] : 0     Crypto Erase Not Supported as part of Secure Erase
   [1:1] : 0x1   Crypto Erase Applies to All Namespace(s)
   [0:0] : 0x1   Format Applies to All Namespace(s)

vwc       : 0x5
   [7:3] : 0x2   Reserved
   [0:0] : 0x1   Volatile Write Cache Present

awun      : 0
awupf     : 0
nvscc     : 0
   [0:0] : 0     NVM Vendor Specific Commands uses Vendor Specific Format

nwpc      : 0
   [2:2] : 0     Permanent Write Protect Not Supported
   [1:1] : 0     Write Protect Until Power Supply Not Supported
   [0:0] : 0     No Write Protect and Write Protect Namespace Not Supported

acwu      : 0
sgls      : 0
  [1:0]  : 0     Scatter-Gather Lists Not Supported

mnan      : 0
subnqn    :
ioccsz    : 0
iorcsz    : 0
icdoff    : 0
ctrattr   : 0
   [0:0] : 0     Dynamic Controller Model

msdbd     : 0
ps    0 : mp:3.30W operational enlat:5 exlat:5 rrt:0 rrl:0
           rwt:0 rwl:0 idle_power:- active_power:-

>>> Also for above device what is the value for the queue block write-zeroes
>>>
>>> parameter that is present in the
>>> /sys/block/<nvmeXnY>/queue/write_zeroes_max_bytes ?
>> $ cat /sys/block/nvme1n1/queue/write_zeroes_max_bytes
>> 131584
> So write-zeroes is configured from the setup.
>>> You can also try blkdiscard -z 0 -l 1024 /dev/<nvmeXnY> to see if the
>>> problem is with
>>> write zeroes.
>> # blkdiscard -z -l 1024 /dev/nvme1n1
>> blkdiscard: /dev/nvme1n1: BLKZEROOUT ioctl failed: Device or resource busy
> This is exactly what I thought, we need to add a quirk for this model
> and make sure
> we don't set the write-zeroes support and make blk-lib emulate the
> write-zeroes.

I am ready to take patches for the NVMe driver to test this out - this 
device is not a boot device and I have no data on it that needs to be 
preserved.

>>> Also can you please also try the latest nvme tree branch nvme-5.11 ?
>>>
>> Where do I get that code from? Is it already in the 5.11-rc tree or do I
>> need to look somewhere else? I checked https://github.com/linux-nvme but
>> I did not see it there.
> Here is the link :-git://git.infradead.org/nvme.git
> Branch 5.12.

I tried fetching the entire repo but it was huge and would have taken a 
long time, so I tried to fetch a single branch instead and got this result:

$ git clone --branch 5.12 --single-branch git://git.infradead.org/nvme.git
Cloning into 'nvme'...
warning: Could not find remote branch 5.12 to clone.
fatal: Remote branch 5.12 not found in upstream origin

I haven't compiled any out-of-tree kernel code in a very long time - how 
easy is it to add this code to a kernel tree and compile it into the 
kernel once I've figured out how to get it?

Brad


From lengchao at huawei.com  Wed Jan 20 22:32:36 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 21 Jan 2021 11:32:36 +0800
Subject: [PATCH 1/5] nvme-core: add cancel tagset helpers
In-Reply-To: <20210121033240.31906-1-lengchao@huawei.com>
References: <20210121033240.31906-1-lengchao@huawei.com>
Message-ID: <20210121033240.31906-2-lengchao@huawei.com>

Add nvme_cancel_tagset and nvme_cancel_admin_tagset for tear down and
reconnection error handling.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 drivers/nvme/host/core.c | 20 ++++++++++++++++++++
 drivers/nvme/host/nvme.h |  2 ++
 2 files changed, 22 insertions(+)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 200bdd672c28..402a433afa55 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -371,6 +371,26 @@ bool nvme_cancel_request(struct request *req, void *data, bool reserved)
 }
 EXPORT_SYMBOL_GPL(nvme_cancel_request);
 
+void nvme_cancel_tagset(struct nvme_ctrl *ctrl)
+{
+	if (ctrl->tagset) {
+		blk_mq_tagset_busy_iter(ctrl->tagset,
+				nvme_cancel_request, ctrl);
+		blk_mq_tagset_wait_completed_request(ctrl->tagset);
+	}
+}
+EXPORT_SYMBOL_GPL(nvme_cancel_tagset);
+
+void nvme_cancel_admin_tagset(struct nvme_ctrl *ctrl)
+{
+	if (ctrl->admin_tagset) {
+		blk_mq_tagset_busy_iter(ctrl->admin_tagset,
+				nvme_cancel_request, ctrl);
+		blk_mq_tagset_wait_completed_request(ctrl->admin_tagset);
+	}
+}
+EXPORT_SYMBOL_GPL(nvme_cancel_admin_tagset);
+
 bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
 		enum nvme_ctrl_state new_state)
 {
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 88a6b97247f5..a72f07181091 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -576,6 +576,8 @@ static inline bool nvme_is_aen_req(u16 qid, __u16 command_id)
 
 void nvme_complete_rq(struct request *req);
 bool nvme_cancel_request(struct request *req, void *data, bool reserved);
+void nvme_cancel_tagset(struct nvme_ctrl *ctrl);
+void nvme_cancel_admin_tagset(struct nvme_ctrl *ctrl);
 bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
 		enum nvme_ctrl_state new_state);
 bool nvme_wait_reset(struct nvme_ctrl *ctrl);
-- 
2.16.4



From lengchao at huawei.com  Wed Jan 20 22:32:37 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 21 Jan 2021 11:32:37 +0800
Subject: [PATCH 2/5] nvme-rdma: add clean action for failed reconnection
In-Reply-To: <20210121033240.31906-1-lengchao@huawei.com>
References: <20210121033240.31906-1-lengchao@huawei.com>
Message-ID: <20210121033240.31906-3-lengchao@huawei.com>

A crash happens when inject failed reconnection.
If reconnect failed after start io queues, the queues will be unquiesced
and new requests continue to be delivered. Reconnection error handling
process directly free queues without cancel suspend requests. The
suppend request will time out, and then crash due to use the queue
after free.

Add sync queues and cancel suppend requests for reconnection error
handling.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 drivers/nvme/host/rdma.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index cf6c49d09c82..d9d677c151af 100644
--- a/drivers/nvme/host/rdma.c
+++ b/drivers/nvme/host/rdma.c
@@ -912,12 +912,16 @@ static int nvme_rdma_configure_admin_queue(struct nvme_rdma_ctrl *ctrl,
 
 	error = nvme_init_identify(&ctrl->ctrl);
 	if (error)
-		goto out_stop_queue;
+		goto out_quiesce_queue;
 
 	return 0;
 
+out_quiesce_queue:
+	blk_mq_quiesce_queue(ctrl->ctrl.admin_q);
+	blk_sync_queue(ctrl->ctrl.admin_q);
 out_stop_queue:
 	nvme_rdma_stop_queue(&ctrl->queues[0]);
+	nvme_cancel_admin_tagset(&ctrl->ctrl);
 out_cleanup_queue:
 	if (new)
 		blk_cleanup_queue(ctrl->ctrl.admin_q);
@@ -994,8 +998,10 @@ static int nvme_rdma_configure_io_queues(struct nvme_rdma_ctrl *ctrl, bool new)
 
 out_wait_freeze_timed_out:
 	nvme_stop_queues(&ctrl->ctrl);
+	nvme_sync_io_queues(&ctrl->ctrl);
 	nvme_rdma_stop_io_queues(ctrl);
 out_cleanup_connect_q:
+	nvme_cancel_tagset(&ctrl->ctrl);
 	if (new)
 		blk_cleanup_queue(ctrl->ctrl.connect_q);
 out_free_tag_set:
@@ -1137,10 +1143,18 @@ static int nvme_rdma_setup_ctrl(struct nvme_rdma_ctrl *ctrl, bool new)
 	return 0;
 
 destroy_io:
-	if (ctrl->ctrl.queue_count > 1)
+	if (ctrl->ctrl.queue_count > 1) {
+		nvme_stop_queues(&ctrl->ctrl);
+		nvme_sync_io_queues(&ctrl->ctrl);
+		nvme_rdma_stop_io_queues(ctrl);
+		nvme_cancel_tagset(&ctrl->ctrl);
 		nvme_rdma_destroy_io_queues(ctrl, new);
+	}
 destroy_admin:
+	blk_mq_quiesce_queue(ctrl->ctrl.admin_q);
+	blk_sync_queue(ctrl->ctrl.admin_q);
 	nvme_rdma_stop_queue(&ctrl->queues[0]);
+	nvme_cancel_admin_tagset(&ctrl->ctrl);
 	nvme_rdma_destroy_admin_queue(ctrl, new);
 	return ret;
 }
-- 
2.16.4



From lengchao at huawei.com  Wed Jan 20 22:32:39 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 21 Jan 2021 11:32:39 +0800
Subject: [PATCH 4/5] nvme-rdma: use cancel tagset helper for tear down
In-Reply-To: <20210121033240.31906-1-lengchao@huawei.com>
References: <20210121033240.31906-1-lengchao@huawei.com>
Message-ID: <20210121033240.31906-5-lengchao@huawei.com>

Use nvme_cancel_tagset and nvme_cancel_admin_tagset to clean code for
tear down process.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 drivers/nvme/host/rdma.c | 12 ++----------
 1 file changed, 2 insertions(+), 10 deletions(-)

diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index d9d677c151af..225828dd7995 100644
--- a/drivers/nvme/host/rdma.c
+++ b/drivers/nvme/host/rdma.c
@@ -1018,11 +1018,7 @@ static void nvme_rdma_teardown_admin_queue(struct nvme_rdma_ctrl *ctrl,
 	blk_mq_quiesce_queue(ctrl->ctrl.admin_q);
 	blk_sync_queue(ctrl->ctrl.admin_q);
 	nvme_rdma_stop_queue(&ctrl->queues[0]);
-	if (ctrl->ctrl.admin_tagset) {
-		blk_mq_tagset_busy_iter(ctrl->ctrl.admin_tagset,
-			nvme_cancel_request, &ctrl->ctrl);
-		blk_mq_tagset_wait_completed_request(ctrl->ctrl.admin_tagset);
-	}
+	nvme_cancel_admin_tagset(&ctrl->ctrl);
 	if (remove)
 		blk_mq_unquiesce_queue(ctrl->ctrl.admin_q);
 	nvme_rdma_destroy_admin_queue(ctrl, remove);
@@ -1036,11 +1032,7 @@ static void nvme_rdma_teardown_io_queues(struct nvme_rdma_ctrl *ctrl,
 		nvme_stop_queues(&ctrl->ctrl);
 		nvme_sync_io_queues(&ctrl->ctrl);
 		nvme_rdma_stop_io_queues(ctrl);
-		if (ctrl->ctrl.tagset) {
-			blk_mq_tagset_busy_iter(ctrl->ctrl.tagset,
-				nvme_cancel_request, &ctrl->ctrl);
-			blk_mq_tagset_wait_completed_request(ctrl->ctrl.tagset);
-		}
+		nvme_cancel_tagset(&ctrl->ctrl);
 		if (remove)
 			nvme_start_queues(&ctrl->ctrl);
 		nvme_rdma_destroy_io_queues(ctrl, remove);
-- 
2.16.4



From lengchao at huawei.com  Wed Jan 20 22:32:38 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 21 Jan 2021 11:32:38 +0800
Subject: [PATCH 3/5] nvme-tcp: add clean action for failed reconnection
In-Reply-To: <20210121033240.31906-1-lengchao@huawei.com>
References: <20210121033240.31906-1-lengchao@huawei.com>
Message-ID: <20210121033240.31906-4-lengchao@huawei.com>

If reconnect failed after start io queues, the queues will be unquiesced
and new requests continue to be delivered. Reconnection error handling
process directly free queues without cancel suspend requests. The
suppend request will time out, and then crash due to use the queue
after free.

Add sync queues and cancel suppend requests for reconnection error
handling.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 drivers/nvme/host/tcp.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 216619926563..7e139d7bd279 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -1809,8 +1809,10 @@ static int nvme_tcp_configure_io_queues(struct nvme_ctrl *ctrl, bool new)
 
 out_wait_freeze_timed_out:
 	nvme_stop_queues(ctrl);
+	nvme_sync_io_queues(ctrl);
 	nvme_tcp_stop_io_queues(ctrl);
 out_cleanup_connect_q:
+	nvme_cancel_tagset(ctrl);
 	if (new)
 		blk_cleanup_queue(ctrl->connect_q);
 out_free_tag_set:
@@ -1872,12 +1874,16 @@ static int nvme_tcp_configure_admin_queue(struct nvme_ctrl *ctrl, bool new)
 
 	error = nvme_init_identify(ctrl);
 	if (error)
-		goto out_stop_queue;
+		goto out_quiesce_queue;
 
 	return 0;
 
+out_quiesce_queue:
+	blk_mq_quiesce_queue(ctrl->admin_q);
+	blk_sync_queue(ctrl->admin_q);
 out_stop_queue:
 	nvme_tcp_stop_queue(ctrl, 0);
+	nvme_cancel_admin_tagset(ctrl);
 out_cleanup_queue:
 	if (new)
 		blk_cleanup_queue(ctrl->admin_q);
@@ -1997,10 +2003,18 @@ static int nvme_tcp_setup_ctrl(struct nvme_ctrl *ctrl, bool new)
 	return 0;
 
 destroy_io:
-	if (ctrl->queue_count > 1)
+	if (ctrl->queue_count > 1) {
+		nvme_stop_queues(ctrl);
+		nvme_sync_io_queues(ctrl);
+		nvme_tcp_stop_io_queues(ctrl);
+		nvme_cancel_tagset(ctrl);
 		nvme_tcp_destroy_io_queues(ctrl, new);
+	}
 destroy_admin:
+	blk_mq_quiesce_queue(ctrl->admin_q);
+	blk_sync_queue(ctrl->admin_q);
 	nvme_tcp_stop_queue(ctrl, 0);
+	nvme_cancel_admin_tagset(ctrl);
 	nvme_tcp_destroy_admin_queue(ctrl, new);
 	return ret;
 }
-- 
2.16.4



From lengchao at huawei.com  Wed Jan 20 22:32:35 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 21 Jan 2021 11:32:35 +0800
Subject: [PATCH 0/5] add clean action for failed reconnection
Message-ID: <20210121033240.31906-1-lengchao@huawei.com>

Reconnection error handling process do not clean suppend requests, this
may cause crash due to use queue after free.
Add helper for clean code.

Chao Leng (5):
  nvme-core: add cancel tagset helpers
  nvme-rdma: add clean action for failed reconnection
  nvme-tcp: add clean action for failed reconnection
  nvme-rdma: use cancel tagset helper for tear down
  nvme-tcp: use cancel tagset helper for tear down

 drivers/nvme/host/core.c | 20 ++++++++++++++++++++
 drivers/nvme/host/nvme.h |  2 ++
 drivers/nvme/host/rdma.c | 30 ++++++++++++++++++------------
 drivers/nvme/host/tcp.c  | 30 ++++++++++++++++++------------
 4 files changed, 58 insertions(+), 24 deletions(-)

-- 
2.16.4



From lengchao at huawei.com  Wed Jan 20 22:32:40 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 21 Jan 2021 11:32:40 +0800
Subject: [PATCH 5/5] nvme-tcp: use cancel tagset helper for tear down
In-Reply-To: <20210121033240.31906-1-lengchao@huawei.com>
References: <20210121033240.31906-1-lengchao@huawei.com>
Message-ID: <20210121033240.31906-6-lengchao@huawei.com>

Use nvme_cancel_tagset and nvme_cancel_admin_tagset to clean code for
tear down process.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 drivers/nvme/host/tcp.c | 12 ++----------
 1 file changed, 2 insertions(+), 10 deletions(-)

diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 7e139d7bd279..312f3f1bb7c0 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -1904,11 +1904,7 @@ static void nvme_tcp_teardown_admin_queue(struct nvme_ctrl *ctrl,
 	blk_mq_quiesce_queue(ctrl->admin_q);
 	blk_sync_queue(ctrl->admin_q);
 	nvme_tcp_stop_queue(ctrl, 0);
-	if (ctrl->admin_tagset) {
-		blk_mq_tagset_busy_iter(ctrl->admin_tagset,
-			nvme_cancel_request, ctrl);
-		blk_mq_tagset_wait_completed_request(ctrl->admin_tagset);
-	}
+	nvme_cancel_admin_tagset(ctrl);
 	if (remove)
 		blk_mq_unquiesce_queue(ctrl->admin_q);
 	nvme_tcp_destroy_admin_queue(ctrl, remove);
@@ -1924,11 +1920,7 @@ static void nvme_tcp_teardown_io_queues(struct nvme_ctrl *ctrl,
 	nvme_stop_queues(ctrl);
 	nvme_sync_io_queues(ctrl);
 	nvme_tcp_stop_io_queues(ctrl);
-	if (ctrl->tagset) {
-		blk_mq_tagset_busy_iter(ctrl->tagset,
-			nvme_cancel_request, ctrl);
-		blk_mq_tagset_wait_completed_request(ctrl->tagset);
-	}
+	nvme_cancel_tagset(ctrl);
 	if (remove)
 		nvme_start_queues(ctrl);
 	nvme_tcp_destroy_io_queues(ctrl, remove);
-- 
2.16.4



From lkp at intel.com  Thu Jan 21 01:09:29 2021
From: lkp at intel.com (kernel test robot)
Date: Thu, 21 Jan 2021 14:09:29 +0800
Subject: [linux-nvme:nvme-5.11] BUILD SUCCESS
 fa0732168fa1369dd089e5b06d6158a68229f7b7
Message-ID: <60091a99.zIgYsOiLVUEr7h9A%lkp@intel.com>

tree/branch: git://git.infradead.org/nvme.git nvme-5.11
branch HEAD: fa0732168fa1369dd089e5b06d6158a68229f7b7  nvme-pci: fix error unwind in nvme_map_data

elapsed time: 725m

configs tested: 196
configs skipped: 2

The following configs have been built successfully.
More configs may be tested in the coming days.

gcc tested configs:
arm64                            allyesconfig
arm64                               defconfig
arm                              allyesconfig
arm                              allmodconfig
arm                                 defconfig
alpha                            alldefconfig
arm                           stm32_defconfig
sparc64                             defconfig
arm                   milbeaut_m10v_defconfig
powerpc                     kilauea_defconfig
sh                     magicpanelr2_defconfig
arc                          axs101_defconfig
sh                   sh7770_generic_defconfig
c6x                              alldefconfig
s390                          debug_defconfig
mips                     cu1830-neo_defconfig
arm                          moxart_defconfig
xtensa                    smp_lx200_defconfig
mips                          malta_defconfig
powerpc                     stx_gp3_defconfig
arm                             pxa_defconfig
mips                        maltaup_defconfig
powerpc                  storcenter_defconfig
powerpc                 mpc836x_mds_defconfig
arm                              alldefconfig
powerpc                         ps3_defconfig
arm                         hackkit_defconfig
powerpc64                           defconfig
m68k                          sun3x_defconfig
ia64                      gensparse_defconfig
sh                            titan_defconfig
arm                        mini2440_defconfig
mips                        nlm_xlr_defconfig
powerpc                 mpc834x_mds_defconfig
xtensa                  cadence_csp_defconfig
powerpc                  mpc885_ads_defconfig
arm                        cerfcube_defconfig
mips                        bcm47xx_defconfig
arm                          ixp4xx_defconfig
arm                            u300_defconfig
arm                    vt8500_v6_v7_defconfig
arm                         cm_x300_defconfig
powerpc                    amigaone_defconfig
openrisc                            defconfig
powerpc                 mpc832x_mds_defconfig
powerpc                      pcm030_defconfig
powerpc                     redwood_defconfig
mips                      pic32mzda_defconfig
ia64                          tiger_defconfig
openrisc                 simple_smp_defconfig
arm                          pcm027_defconfig
arc                        nsim_700_defconfig
m68k                           sun3_defconfig
sh                  sh7785lcr_32bit_defconfig
mips                       lemote2f_defconfig
mips                   sb1250_swarm_defconfig
sh                           se7724_defconfig
mips                     decstation_defconfig
mips                         bigsur_defconfig
xtensa                              defconfig
sparc                               defconfig
h8300                    h8300h-sim_defconfig
powerpc                     ppa8548_defconfig
arm                         nhk8815_defconfig
powerpc                    klondike_defconfig
powerpc                     rainier_defconfig
parisc                generic-32bit_defconfig
arm                          pxa168_defconfig
powerpc                 mpc834x_itx_defconfig
mips                            ar7_defconfig
ia64                        generic_defconfig
mips                        jmr3927_defconfig
riscv                             allnoconfig
xtensa                         virt_defconfig
i386                             alldefconfig
arm                           sunxi_defconfig
arc                     haps_hs_smp_defconfig
sh                        edosk7760_defconfig
sparc64                          alldefconfig
arm                             ezx_defconfig
m68k                         apollo_defconfig
arm                     am200epdkit_defconfig
powerpc                mpc7448_hpc2_defconfig
arm                       spear13xx_defconfig
xtensa                generic_kc705_defconfig
m68k                             alldefconfig
sh                           se7712_defconfig
arm                           spitz_defconfig
powerpc                      arches_defconfig
powerpc                       ppc64_defconfig
mips                      pistachio_defconfig
powerpc                 mpc837x_mds_defconfig
arm                        oxnas_v6_defconfig
arm                         bcm2835_defconfig
sh                          sdk7786_defconfig
sparc                       sparc32_defconfig
mips                        nlm_xlp_defconfig
mips                         tb0287_defconfig
powerpc                    ge_imp3a_defconfig
mips                      malta_kvm_defconfig
powerpc                     asp8347_defconfig
powerpc                      ppc6xx_defconfig
arm                          iop32x_defconfig
sparc                            alldefconfig
powerpc                        cell_defconfig
csky                             alldefconfig
arm                         mv78xx0_defconfig
mips                           ip32_defconfig
mips                      maltasmvp_defconfig
ia64                             allmodconfig
ia64                                defconfig
ia64                             allyesconfig
m68k                             allmodconfig
m68k                                defconfig
m68k                             allyesconfig
nios2                               defconfig
arc                              allyesconfig
nds32                             allnoconfig
c6x                              allyesconfig
nds32                               defconfig
nios2                            allyesconfig
csky                                defconfig
alpha                               defconfig
alpha                            allyesconfig
xtensa                           allyesconfig
h8300                            allyesconfig
arc                                 defconfig
sh                               allmodconfig
parisc                              defconfig
s390                             allyesconfig
parisc                           allyesconfig
s390                                defconfig
i386                             allyesconfig
sparc                            allyesconfig
i386                               tinyconfig
i386                                defconfig
mips                             allyesconfig
mips                             allmodconfig
powerpc                          allyesconfig
powerpc                          allmodconfig
powerpc                           allnoconfig
i386                 randconfig-a001-20210120
i386                 randconfig-a002-20210120
i386                 randconfig-a004-20210120
i386                 randconfig-a005-20210120
i386                 randconfig-a003-20210120
i386                 randconfig-a006-20210120
i386                 randconfig-a001-20210121
i386                 randconfig-a002-20210121
i386                 randconfig-a004-20210121
i386                 randconfig-a006-20210121
i386                 randconfig-a005-20210121
i386                 randconfig-a003-20210121
x86_64               randconfig-a012-20210120
x86_64               randconfig-a015-20210120
x86_64               randconfig-a016-20210120
x86_64               randconfig-a011-20210120
x86_64               randconfig-a013-20210120
x86_64               randconfig-a014-20210120
x86_64               randconfig-a002-20210121
x86_64               randconfig-a003-20210121
x86_64               randconfig-a001-20210121
x86_64               randconfig-a005-20210121
x86_64               randconfig-a006-20210121
x86_64               randconfig-a004-20210121
i386                 randconfig-a013-20210120
i386                 randconfig-a011-20210120
i386                 randconfig-a012-20210120
i386                 randconfig-a014-20210120
i386                 randconfig-a015-20210120
i386                 randconfig-a016-20210120
i386                 randconfig-a013-20210121
i386                 randconfig-a011-20210121
i386                 randconfig-a012-20210121
i386                 randconfig-a014-20210121
i386                 randconfig-a015-20210121
i386                 randconfig-a016-20210121
riscv                    nommu_k210_defconfig
riscv                            allyesconfig
riscv                    nommu_virt_defconfig
riscv                               defconfig
riscv                          rv32_defconfig
riscv                            allmodconfig
x86_64                                   rhel
x86_64                           allyesconfig
x86_64                    rhel-7.6-kselftests
x86_64                              defconfig
x86_64                               rhel-8.3
x86_64                      rhel-8.3-kbuiltin
x86_64                                  kexec

clang tested configs:
x86_64               randconfig-a002-20210120
x86_64               randconfig-a003-20210120
x86_64               randconfig-a001-20210120
x86_64               randconfig-a005-20210120
x86_64               randconfig-a006-20210120
x86_64               randconfig-a004-20210120

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all at lists.01.org


From lengchao at huawei.com  Thu Jan 21 02:03:25 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 21 Jan 2021 15:03:25 +0800
Subject: [PATCH v3 0/5] avoid double request completion and IO error
Message-ID: <20210121070330.19701-1-lengchao@huawei.com>

Add blk_mq_set_request_complete and nvme_complete_failed_req for two bug
fixs.
First avoid double request completion for nvmf_fail_nonready_command.
Second avoid IO error for nvme native multipath.

V3:
	- complete the request just for HBA driver path related error.
V2:
	- use "switch" instead "if" to check return status.

Chao Leng (5):
  blk-mq: introduce blk_mq_set_request_complete
  nvme-core: introduce complete failed request
  nvme-fabrics: avoid double request completion for
    nvmf_fail_nonready_command
  nvme-rdma: avoid IO error for nvme native multipath
  nvme-fc: avoid IO error for nvme native multipath

 drivers/nvme/host/fabrics.c | 4 +---
 drivers/nvme/host/fc.c      | 7 ++++++-
 drivers/nvme/host/nvme.h    | 8 ++++++++
 drivers/nvme/host/rdma.c    | 9 ++++++++-
 include/linux/blk-mq.h      | 5 +++++
 5 files changed, 28 insertions(+), 5 deletions(-)

-- 
2.16.4



From lengchao at huawei.com  Thu Jan 21 02:03:26 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 21 Jan 2021 15:03:26 +0800
Subject: [PATCH v3 1/5] blk-mq: introduce blk_mq_set_request_complete
In-Reply-To: <20210121070330.19701-1-lengchao@huawei.com>
References: <20210121070330.19701-1-lengchao@huawei.com>
Message-ID: <20210121070330.19701-2-lengchao@huawei.com>

nvme drivers need to set the state of request to MQ_RQ_COMPLETE when
directly complete request in queue_rq.
So add blk_mq_set_request_complete.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 include/linux/blk-mq.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h
index 47b021952ac7..fc096b04bb7a 100644
--- a/include/linux/blk-mq.h
+++ b/include/linux/blk-mq.h
@@ -494,6 +494,11 @@ static inline int blk_mq_request_completed(struct request *rq)
 	return blk_mq_rq_state(rq) == MQ_RQ_COMPLETE;
 }
 
+static inline void blk_mq_set_request_complete(struct request *rq)
+{
+	WRITE_ONCE(rq->state, MQ_RQ_COMPLETE);
+}
+
 void blk_mq_start_request(struct request *rq);
 void blk_mq_end_request(struct request *rq, blk_status_t error);
 void __blk_mq_end_request(struct request *rq, blk_status_t error);
-- 
2.16.4



From lengchao at huawei.com  Thu Jan 21 02:03:27 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 21 Jan 2021 15:03:27 +0800
Subject: [PATCH v3 2/5] nvme-core: introduce complete failed request
In-Reply-To: <20210121070330.19701-1-lengchao@huawei.com>
References: <20210121070330.19701-1-lengchao@huawei.com>
Message-ID: <20210121070330.19701-3-lengchao@huawei.com>

Work with nvme native multipath, if a path related error occurs when
queue_rq call HBA drive to send request, queue_rq need complete the
request with NVME_SC_HOST_PATH_ERROR, the request will fail over to
retry if needed.
So introduce nvme_complete_failed_req for queue_rq and
nvmf_fail_nonready_command.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 drivers/nvme/host/nvme.h | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 88a6b97247f5..01fb54ba3d1f 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -575,6 +575,14 @@ static inline bool nvme_is_aen_req(u16 qid, __u16 command_id)
 }
 
 void nvme_complete_rq(struct request *req);
+
+static inline void nvme_complete_failed_req(struct request *req)
+{
+	nvme_req(req)->status = NVME_SC_HOST_PATH_ERROR;
+	blk_mq_set_request_complete(req);
+	nvme_complete_rq(req);
+}
+
 bool nvme_cancel_request(struct request *req, void *data, bool reserved);
 bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
 		enum nvme_ctrl_state new_state);
-- 
2.16.4



From lengchao at huawei.com  Thu Jan 21 02:03:29 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 21 Jan 2021 15:03:29 +0800
Subject: [PATCH v3 4/5] nvme-rdma: avoid IO error for nvme native multipath
In-Reply-To: <20210121070330.19701-1-lengchao@huawei.com>
References: <20210121070330.19701-1-lengchao@huawei.com>
Message-ID: <20210121070330.19701-5-lengchao@huawei.com>

Work with nvme native multipath, if a path related error occurs when
queue_rq call HBA drive to send request, queue_rq will return
BLK_STS_IOERR to blk-mq. The request is completed with BLK_STS_IOERR
instead of fail over to retry.
queue_rq need call nvme_complete_rq to complete the request with
NVME_SC_HOST_PATH_ERROR, the request will fail over to retry if needed.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 drivers/nvme/host/rdma.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index cf6c49d09c82..5fb0838a5f8b 100644
--- a/drivers/nvme/host/rdma.c
+++ b/drivers/nvme/host/rdma.c
@@ -2030,6 +2030,7 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
 	bool queue_ready = test_bit(NVME_RDMA_Q_LIVE, &queue->flags);
 	blk_status_t ret;
 	int err;
+	bool driver_error = false;
 
 	WARN_ON_ONCE(rq->tag < 0);
 
@@ -2077,8 +2078,10 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
 
 	err = nvme_rdma_post_send(queue, sqe, req->sge, req->num_sge,
 			req->mr ? &req->reg_wr.wr : NULL);
-	if (unlikely(err))
+	if (unlikely(err)) {
+		driver_error = true;
 		goto err_unmap;
+	}
 
 	return BLK_STS_OK;
 
@@ -2093,6 +2096,10 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
 unmap_qe:
 	ib_dma_unmap_single(dev, req->sqe.dma, sizeof(struct nvme_command),
 			    DMA_TO_DEVICE);
+	if (driver_error && ret == BLK_STS_IOERR) {
+		nvme_complete_failed_req(rq);
+		ret = BLK_STS_OK;
+	}
 	return ret;
 }
 
-- 
2.16.4



From lengchao at huawei.com  Thu Jan 21 02:03:30 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 21 Jan 2021 15:03:30 +0800
Subject: [PATCH v3 5/5] nvme-fc: avoid IO error for nvme native multipath
In-Reply-To: <20210121070330.19701-1-lengchao@huawei.com>
References: <20210121070330.19701-1-lengchao@huawei.com>
Message-ID: <20210121070330.19701-6-lengchao@huawei.com>

Work with nvme native multipath, if a path related error occurs when
queue_rq call HBA drive to send request, queue_rq will return
BLK_STS_IOERR to blk-mq. The request is completed with BLK_STS_IOERR
instead of fail over to retry.
queue_rq need call nvme_complete_rq to complete the request with
NVME_SC_HOST_PATH_ERROR, the request will fail over to retry if needed.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 drivers/nvme/host/fc.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c
index 5f36cfa8136c..ebc9911f9528 100644
--- a/drivers/nvme/host/fc.c
+++ b/drivers/nvme/host/fc.c
@@ -2791,7 +2791,12 @@ nvme_fc_queue_rq(struct blk_mq_hw_ctx *hctx,
 	}
 
 
-	return nvme_fc_start_fcp_op(ctrl, queue, op, data_len, io_dir);
+	ret = nvme_fc_start_fcp_op(ctrl, queue, op, data_len, io_dir);
+	if (ret == BLK_STS_IOERR) {
+		nvme_complete_failed_req(rq);
+		ret = BLK_STS_OK;
+	}
+	return ret;
 }
 
 static void
-- 
2.16.4



From lengchao at huawei.com  Thu Jan 21 02:03:28 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 21 Jan 2021 15:03:28 +0800
Subject: [PATCH v3 3/5] nvme-fabrics: avoid double request completion for
 nvmf_fail_nonready_command
In-Reply-To: <20210121070330.19701-1-lengchao@huawei.com>
References: <20210121070330.19701-1-lengchao@huawei.com>
Message-ID: <20210121070330.19701-4-lengchao@huawei.com>

When reconnect, the request may be completed with NVME_SC_HOST_PATH_ERROR
in nvmf_fail_nonready_command. The state of request will be changed to
MQ_RQ_IN_FLIGHT before call nvme_complete_rq. If free the request
asynchronously such as in nvme_submit_user_cmd, in extreme scenario
the request may be completed again in tear down process.
nvmf_fail_nonready_command do not need calling blk_mq_start_request
before complete the request. nvmf_fail_nonready_command should set
the state of request to MQ_RQ_COMPLETE before complete the request.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 drivers/nvme/host/fabrics.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c
index 72ac00173500..874e4320e214 100644
--- a/drivers/nvme/host/fabrics.c
+++ b/drivers/nvme/host/fabrics.c
@@ -553,9 +553,7 @@ blk_status_t nvmf_fail_nonready_command(struct nvme_ctrl *ctrl,
 	    !blk_noretry_request(rq) && !(rq->cmd_flags & REQ_NVME_MPATH))
 		return BLK_STS_RESOURCE;
 
-	nvme_req(rq)->status = NVME_SC_HOST_PATH_ERROR;
-	blk_mq_start_request(rq);
-	nvme_complete_rq(rq);
+	nvme_complete_failed_req(rq);
 	return BLK_STS_OK;
 }
 EXPORT_SYMBOL_GPL(nvmf_fail_nonready_command);
-- 
2.16.4



From Chaitanya.Kulkarni at wdc.com  Thu Jan 21 03:08:58 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Thu, 21 Jan 2021 08:08:58 +0000
Subject: [PATCH 1/1] nvme: update enumerations for status codes
References: <20210104125947.160984-1-mgurtovoy@nvidia.com>
 <BYAPR04MB4965E1DC0180C2E5789E505186A20@BYAPR04MB4965.namprd04.prod.outlook.com>
 <55ebc8c7-5631-1f99-1384-80ca85c26b0d@nvidia.com>
Message-ID: <DM6PR04MB4972577AACC08ECFB620E54C86A10@DM6PR04MB4972.namprd04.prod.outlook.com>

On 1/20/21 2:03 AM, Max Gurtovoy wrote:
> On 1/20/2021 7:09 AM, Chaitanya Kulkarni wrote:
>> Max,
>> On 1/4/21 04:59, Max Gurtovoy wrote:
>>> All the updates are mentioned in the ratified NVMe 1.4 spec.
>>>
>>> Signed-off-by: Max Gurtovoy <mgurtovoy at nvidia.com>
>>> ---
>> I'm not against keeping the header file up to date with the spec,
>> but should we add the error status into the kernel code even if
>> we are not using it in the host/target driver ?
> I we go with this approach we should remove half of the code inside nvme.h
Yes you are right and I really don't understand the need to add symbols
when they are not used I think I'm also guilty of some :P.

It will be great if someone can clarify the need to add symbols when they
arenot used in the kernel or a use case which needs this sort of update.
>
>> Here we add 24 lines which we have not used at all.
>>>   include/linux/nvme.h | 24 ++++++++++++++++++++----
>>>   1 file changed, 20 insertions(+), 4 deletions(-)
>>>
>> Regarding the nvme-cli this is much needed a sync since it does
>> decode all the errors if I'm not wrong.
> I can sync it in V2.
>
>



From hare at suse.de  Thu Jan 21 03:14:11 2021
From: hare at suse.de (Hannes Reinecke)
Date: Thu, 21 Jan 2021 09:14:11 +0100
Subject: [PATCH v2 2/6] nvme-core: introduce complete failed request
In-Reply-To: <20210107033149.15701-3-lengchao@huawei.com>
References: <20210107033149.15701-1-lengchao@huawei.com>
 <20210107033149.15701-3-lengchao@huawei.com>
Message-ID: <93e16361-6973-5245-b040-692ef2ec4d79@suse.de>

On 1/7/21 4:31 AM, Chao Leng wrote:
> When a request is queued failed, if the fail status is not
> BLK_STS_RESOURCE, BLK_STS_DEV_RESOURCE, BLK_STS_ZONE_RESOURCE,
> the request is need to complete with nvme_complete_rq in queue_rq.
> So introduce nvme_try_complete_failed_req.
> The request is needed to complete with NVME_SC_HOST_PATH_ERROR in
> nvmf_fail_nonready_command and queue_rq.
> So introduce nvme_complete_failed_req.
> For details, see the subsequent patches.
> 
> Signed-off-by: Chao Leng <lengchao at huawei.com>
> ---
>   drivers/nvme/host/nvme.h | 21 +++++++++++++++++++++
>   1 file changed, 21 insertions(+)
> 
> diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
> index bfcedfa4b057..fc4eefdfbb34 100644
> --- a/drivers/nvme/host/nvme.h
> +++ b/drivers/nvme/host/nvme.h
> @@ -649,6 +649,27 @@ void nvme_put_ns_from_disk(struct nvme_ns_head *head, int idx);
>   extern const struct attribute_group *nvme_ns_id_attr_groups[];
>   extern const struct block_device_operations nvme_ns_head_ops;
>   
> +static inline void nvme_complete_failed_req(struct request *req)
> +{
> +	nvme_req(req)->status = NVME_SC_HOST_PATH_ERROR;
> +	blk_mq_set_request_complete(req);
> +	nvme_complete_rq(req);
> +}
> +
> +static inline blk_status_t nvme_try_complete_failed_req(struct request *req,
> +							blk_status_t ret)
> +{
> +	switch (ret) {
> +	case BLK_STS_RESOURCE:
> +	case BLK_STS_DEV_RESOURCE:
> +	case BLK_STS_ZONE_RESOURCE:
> +		return ret;
> +	default:
> +		nvme_complete_failed_req(req);
> +		return BLK_STS_OK;
> +	}
> +}
> +
>   #ifdef CONFIG_NVME_MULTIPATH
>   static inline bool nvme_ctrl_use_ana(struct nvme_ctrl *ctrl)
>   {
> 
This is not correct.
HOST_PATH_ERROR only should be set _iff_ it is a pathing issue, and the 
HBA/transport is equipped to determine that.
Any other error have other causes, and we need to look at the individual 
error codes (and situations) to determine if this really is a pathing error.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare at suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 N?rnberg
HRB 36809 (AG N?rnberg), Gesch?ftsf?hrer: Felix Imend?rffer


From Chaitanya.Kulkarni at wdc.com  Thu Jan 21 03:23:20 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Thu, 21 Jan 2021 08:23:20 +0000
Subject: [RFC PATCH 00/37] block: introduce bio_init_fields()
References: <20210119050631.57073-1-chaitanya.kulkarni@wdc.com>
 <CAGRGNgWLspr6M1COgX9cuDDgYdiXvQQjWQb7XYLsmFpfMYt0sA@mail.gmail.com>
Message-ID: <DM6PR04MB4972029B58F81B22033E31F386A10@DM6PR04MB4972.namprd04.prod.outlook.com>

On 1/20/21 7:01 PM, Julian Calaby wrote:
> Hi Chaitanya,
>
> On Tue, Jan 19, 2021 at 5:01 PM Chaitanya Kulkarni
> <chaitanya.kulkarni at wdc.com> wrote:
>> Hi,
>>
>> This is a *compile only RFC* which adds a generic helper to initialize
>> the various fields of the bio that is repeated all the places in
>> file-systems, block layer, and drivers.
>>
>> The new helper allows callers to initialize various members such as
>> bdev, sector, private, end io callback, io priority, and write hints.
>>
>> The objective of this RFC is to only start a discussion, this it not
>> completely tested at all.
>> Following diff shows code level benefits of this helper :-
>>  38 files changed, 124 insertions(+), 236 deletions(-)
> On a more abstract note, I don't think this diffstat is actually
> illustrating the benefits of this as much as you think it is.
>
> Yeah, we've reduced the code by 112 lines, but that's barely half the
> curn here. It looks, from the diffstat, that you've effectively
> reduced 2 lines into 1. That isn't much of a saving.
>
> Thanks,
The diff stat is not the only measure since every component fs/driver
has a different style and nested call it just to show the effect.
Thanks for your comment, we have decided to go with the bio_new approach.




From hare at suse.de  Thu Jan 21 03:25:39 2021
From: hare at suse.de (Hannes Reinecke)
Date: Thu, 21 Jan 2021 09:25:39 +0100
Subject: kernel oops after nvme_set_queue_count()
Message-ID: <d5f00c36-2981-0a0c-7a6d-b4ab2c8d139e@suse.de>

Hi all,

a customer of ours ran into this oops:

[44157.918962] nvme nvme5: I/O 22 QID 0 timeout
[44163.347467] nvme nvme5: Could not set queue count (880)
[44163.347551] nvme nvme5: Successfully reconnected (6 attempts)
[44168.414977] BUG: unable to handle kernel paging request at 
ffff888e261e7808
[44168.414988] IP: 0xffff888e261e7808
[44168.414994] PGD 98c2ae067 P4D 98c2ae067 PUD f57937063 PMD 
8000000f660001e3

It's related to this code snippet in drivers/nvme/host/core.c

	/*
	 * Degraded controllers might return an error when setting the queue
	 * count.  We still want to be able to bring them online and offer
	 * access to the admin queue, as that might be only way to fix them up.
	 */
	if (status > 0) {
		dev_err(ctrl->device, "Could not set queue count (%d)\n", status);
		*count = 0;


causing nvme_set_queue_count() _not_ to return an error, but rather let 
the reconnect complete.
Of course, as this failure is due to a timeout (cf the status code; 880
is NVME_SC_HOST_PATH_ERROR), the admin queue has been torn down by the 
transport, causing this crash.

So, question: _why_ do we ignore the status?

For fabrics I completely fail to see the reason here; even _if_ it 
worked we would end up with a connection for which just the admin queue 
is operable, the state is LIVE, and all information we could glance 
would indicate that the connection is perfectly healthy.
It just doesn't have any I/O queues.
Which will lead to some very confused customers and some very unhappy 
support folks trying to figure out what has happened.

Can we just kill this statement and always return an error?
In all other cases we are quite trigger-happy with controller reset; why 
not here?

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare at suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 N?rnberg
HRB 36809 (AG N?rnberg), Gesch?ftsf?hrer: Felix Imend?rffer


From hch at infradead.org  Thu Jan 21 03:32:42 2021
From: hch at infradead.org (Christoph Hellwig)
Date: Thu, 21 Jan 2021 09:32:42 +0100
Subject: [GIT PULL] nvme fixes for 5.11
Message-ID: <YAk8Kt/DRZ7T6WBl@infradead.org>

The following changes since commit b4f664252f51e119e9403ef84b6e9ff36d119510:

  Merge tag 'nvme-5.11-2021-01-14' of git://git.infradead.org/nvme into block-5.11 (2021-01-14 15:17:33 -0700)

are available in the Git repository at:

  git://git.infradead.org/nvme.git tags/nvme-5.11-2020-01-21

for you to fetch changes up to fa0732168fa1369dd089e5b06d6158a68229f7b7:

  nvme-pci: fix error unwind in nvme_map_data (2021-01-20 18:56:33 +0100)

----------------------------------------------------------------
nvme fixes for 5.11:

 - fix a status code in nvmet (Chaitanya Kulkarni)
 - avoid double completions in nvme-rdma/nvme-tcp (Chao Leng)
 - fix the CMB support to cope with NVMe 1.4 controllers (Klaus Jensen)
 - fix PRINFO handling in the passthrough ioctl (Revanth Rajashekar)
 - fix a double DMA unmap in nvme-pci

----------------------------------------------------------------
Chaitanya Kulkarni (1):
      nvmet: set right status on error in id-ns handler

Chao Leng (2):
      nvme-rdma: avoid request double completion for concurrent nvme_rdma_timeout
      nvme-tcp: avoid request double completion for concurrent nvme_tcp_timeout

Christoph Hellwig (2):
      nvme-pci: refactor nvme_unmap_data
      nvme-pci: fix error unwind in nvme_map_data

Klaus Jensen (1):
      nvme-pci: allow use of cmb on v1.4 controllers

Revanth Rajashekar (1):
      nvme: check the PRINFO bit before deciding the host buffer length

 drivers/nvme/host/core.c        |  17 +++++-
 drivers/nvme/host/pci.c         | 119 +++++++++++++++++++++++++++-------------
 drivers/nvme/host/rdma.c        |  15 +++--
 drivers/nvme/host/tcp.c         |  14 +++--
 drivers/nvme/target/admin-cmd.c |   8 ++-
 include/linux/nvme.h            |   6 ++
 6 files changed, 129 insertions(+), 50 deletions(-)


From hch at lst.de  Thu Jan 21 03:40:59 2021
From: hch at lst.de (Christoph Hellwig)
Date: Thu, 21 Jan 2021 09:40:59 +0100
Subject: [PATCH v3 1/5] blk-mq: introduce blk_mq_set_request_complete
In-Reply-To: <20210121070330.19701-2-lengchao@huawei.com>
References: <20210121070330.19701-1-lengchao@huawei.com>
 <20210121070330.19701-2-lengchao@huawei.com>
Message-ID: <20210121084059.GA25963@lst.de>

On Thu, Jan 21, 2021 at 03:03:26PM +0800, Chao Leng wrote:
> nvme drivers need to set the state of request to MQ_RQ_COMPLETE when
> directly complete request in queue_rq.
> So add blk_mq_set_request_complete.

So I'm not happy with this helper.  It should at least:

 a) be named and documented to only apply for the ->queue_rq fa?lure case
 b) check that the request is in MQ_RQ_IDLE state


From hch at lst.de  Thu Jan 21 03:41:50 2021
From: hch at lst.de (Christoph Hellwig)
Date: Thu, 21 Jan 2021 09:41:50 +0100
Subject: [PATCH v3 2/5] nvme-core: introduce complete failed request
In-Reply-To: <20210121070330.19701-3-lengchao@huawei.com>
References: <20210121070330.19701-1-lengchao@huawei.com>
 <20210121070330.19701-3-lengchao@huawei.com>
Message-ID: <20210121084150.GB25963@lst.de>

> +static inline void nvme_complete_failed_req(struct request *req)

I think the name is too generic, and the function also needs a little
comment, especially as it forces a specific error code.

> +{
> +	nvme_req(req)->status = NVME_SC_HOST_PATH_ERROR;
> +	blk_mq_set_request_complete(req);
> +	nvme_complete_rq(req);
> +}

Also no need to mark this as an inline function.


From hare at suse.de  Thu Jan 21 03:58:37 2021
From: hare at suse.de (Hannes Reinecke)
Date: Thu, 21 Jan 2021 09:58:37 +0100
Subject: [PATCH v3 3/5] nvme-fabrics: avoid double request completion for
 nvmf_fail_nonready_command
In-Reply-To: <20210121070330.19701-4-lengchao@huawei.com>
References: <20210121070330.19701-1-lengchao@huawei.com>
 <20210121070330.19701-4-lengchao@huawei.com>
Message-ID: <fda1fdb8-8a9d-2e95-4d08-8d8ee1df450d@suse.de>

On 1/21/21 8:03 AM, Chao Leng wrote:
> When reconnect, the request may be completed with NVME_SC_HOST_PATH_ERROR
> in nvmf_fail_nonready_command. The state of request will be changed to
> MQ_RQ_IN_FLIGHT before call nvme_complete_rq. If free the request
> asynchronously such as in nvme_submit_user_cmd, in extreme scenario
> the request may be completed again in tear down process.
> nvmf_fail_nonready_command do not need calling blk_mq_start_request
> before complete the request. nvmf_fail_nonready_command should set
> the state of request to MQ_RQ_COMPLETE before complete the request.
> 

So what you are saying is that there is a race condition between
blk_mq_start_request()
and
nvme_complete_request()

> Signed-off-by: Chao Leng <lengchao at huawei.com>
> ---
>   drivers/nvme/host/fabrics.c | 4 +---
>   1 file changed, 1 insertion(+), 3 deletions(-)
> 
> diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c
> index 72ac00173500..874e4320e214 100644
> --- a/drivers/nvme/host/fabrics.c
> +++ b/drivers/nvme/host/fabrics.c
> @@ -553,9 +553,7 @@ blk_status_t nvmf_fail_nonready_command(struct nvme_ctrl *ctrl,
>   	    !blk_noretry_request(rq) && !(rq->cmd_flags & REQ_NVME_MPATH))
>   		return BLK_STS_RESOURCE;
>   
> -	nvme_req(rq)->status = NVME_SC_HOST_PATH_ERROR;
> -	blk_mq_start_request(rq);
> -	nvme_complete_rq(rq);
> +	nvme_complete_failed_req(rq);
>   	return BLK_STS_OK;
>   }
>   EXPORT_SYMBOL_GPL(nvmf_fail_nonready_command);
> I'd rather have 'nvme_complete_failed_req()' accept the status as 
argument, like

nvme_complete_failed_request(rq, NVME_SC_HOST_PATH_ERROR)

that way it's obvious what is happening, and the status isn't hidden in 
the function.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare at suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 N?rnberg
HRB 36809 (AG N?rnberg), Gesch?ftsf?hrer: Felix Imend?rffer


From hch at lst.de  Thu Jan 21 04:00:12 2021
From: hch at lst.de (Christoph Hellwig)
Date: Thu, 21 Jan 2021 10:00:12 +0100
Subject: [PATCH v3 3/5] nvme-fabrics: avoid double request completion
 for nvmf_fail_nonready_command
In-Reply-To: <fda1fdb8-8a9d-2e95-4d08-8d8ee1df450d@suse.de>
References: <20210121070330.19701-1-lengchao@huawei.com>
 <20210121070330.19701-4-lengchao@huawei.com>
 <fda1fdb8-8a9d-2e95-4d08-8d8ee1df450d@suse.de>
Message-ID: <20210121090012.GA27342@lst.de>

On Thu, Jan 21, 2021 at 09:58:37AM +0100, Hannes Reinecke wrote:
> On 1/21/21 8:03 AM, Chao Leng wrote:
>> When reconnect, the request may be completed with NVME_SC_HOST_PATH_ERROR
>> in nvmf_fail_nonready_command. The state of request will be changed to
>> MQ_RQ_IN_FLIGHT before call nvme_complete_rq. If free the request
>> asynchronously such as in nvme_submit_user_cmd, in extreme scenario
>> the request may be completed again in tear down process.
>> nvmf_fail_nonready_command do not need calling blk_mq_start_request
>> before complete the request. nvmf_fail_nonready_command should set
>> the state of request to MQ_RQ_COMPLETE before complete the request.
>>
>
> So what you are saying is that there is a race condition between
> blk_mq_start_request()
> and
> nvme_complete_request()

Between those to a teardwon that cancels all requests can come in.


From sagi at grimberg.me  Thu Jan 21 04:06:22 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Thu, 21 Jan 2021 01:06:22 -0800
Subject: kernel oops after nvme_set_queue_count()
In-Reply-To: <d5f00c36-2981-0a0c-7a6d-b4ab2c8d139e@suse.de>
References: <d5f00c36-2981-0a0c-7a6d-b4ab2c8d139e@suse.de>
Message-ID: <7b532e99-8d94-28c1-6e82-bb1d9eb4b439@grimberg.me>


> Hi all,
> 
> a customer of ours ran into this oops:
> 
> [44157.918962] nvme nvme5: I/O 22 QID 0 timeout
> [44163.347467] nvme nvme5: Could not set queue count (880)
> [44163.347551] nvme nvme5: Successfully reconnected (6 attempts)
> [44168.414977] BUG: unable to handle kernel paging request at 
> ffff888e261e7808
> [44168.414988] IP: 0xffff888e261e7808
> [44168.414994] PGD 98c2ae067 P4D 98c2ae067 PUD f57937063 PMD 
> 8000000f660001e3
> 
> It's related to this code snippet in drivers/nvme/host/core.c
> 
>  ????/*
>  ???? * Degraded controllers might return an error when setting the queue
>  ???? * count.? We still want to be able to bring them online and offer
>  ???? * access to the admin queue, as that might be only way to fix them 
> up.
>  ???? */
>  ????if (status > 0) {
>  ??????? dev_err(ctrl->device, "Could not set queue count (%d)\n", status);
>  ??????? *count = 0;
> 
> 
> causing nvme_set_queue_count() _not_ to return an error, but rather let 
> the reconnect complete.
> Of course, as this failure is due to a timeout (cf the status code; 880
> is NVME_SC_HOST_PATH_ERROR), the admin queue has been torn down by the 
> transport, causing this crash.
> 
> So, question: _why_ do we ignore the status?

This used to exist in pci where a controller reset will fail to set up
I/O queues, at least the controller can accept admin commands to get
some diagnostics (perhaps an error log page).

> For fabrics I completely fail to see the reason here; even _if_ it 
> worked we would end up with a connection for which just the admin queue 
> is operable, the state is LIVE, and all information we could glance 
> would indicate that the connection is perfectly healthy.

We also had a ADMIN_ONLY state at some point, but that was dropped as
well for reasons I don't remember at the moment.

> It just doesn't have any I/O queues.
> Which will lead to some very confused customers and some very unhappy 
> support folks trying to figure out what has happened.
> 
> Can we just kill this statement and always return an error?
> In all other cases we are quite trigger-happy with controller reset; why 
> not here?

I think we will want to keep the existing behavior for pci, but agree we
probably want to change it for fabrics...


From mgurtovoy at nvidia.com  Thu Jan 21 04:09:45 2021
From: mgurtovoy at nvidia.com (Max Gurtovoy)
Date: Thu, 21 Jan 2021 09:09:45 +0000
Subject: [PATCH v2 0/2] Resync Linux and NVMe-cli nvme.h header
Message-ID: <20210121090948.8027-1-mgurtovoy@nvidia.com>

Hi Christoph/Sagi/Keith/Chaitanya,
This series introduce synchronization between the kernel
include/linux/nvme.h and nvme-cli linux/nvme.h to ease on maintainance
of both.
The changes for nvme-cli are in the structure of the linux/nvme.h header
file that will be divided to 2 parts: nvme-cli specific code and an
identical copy of the content of include/linux/nvme.h from Linux.
In this way, the resync process will be ease and whole the content of
include/linux/nvme.h will be pasted to that area. Individual commits to
this area will be forbidden and must go through kernel part first.

The additional to Linux include/linux/nvme.h is new enumerations from
NVMe 1.4 specification and the missing parts from nvme-cli that are
originated in common area of the code.

The structures and enumeration that were intruduced only to nvme-cli
were moved to part #1 in nvme-cli linux/nvme.h file and we can decide
whether we need them in the kernel as well. This can be done in future
step. Also new nvme-cli specifics that are not a must in the kernel and
are not in the common code structures/enums can go there.

To test this I run some basic commands as:
- nvme list
- nvme list -v
- nvme list-subsys
- nvme connect/disconnect
- nvme id-ctrl
- nvme id-ns

changes from V1:
 - Added Reviewed-by signature for patch 1/2 (from Hannes)
 - Added resync patch 2/2
 - Added resync nvme-cli patch 1/1

Max Gurtovoy (2):
  nvme: update enumerations for status codes
  nvme: resync header file with common nvme-cli tool

 include/linux/nvme.h | 90 +++++++++++++++++++++++++++++++++++---------
 1 file changed, 72 insertions(+), 18 deletions(-)

-- 
2.25.4



From mgurtovoy at nvidia.com  Thu Jan 21 04:09:47 2021
From: mgurtovoy at nvidia.com (Max Gurtovoy)
Date: Thu, 21 Jan 2021 09:09:47 +0000
Subject: [PATCH 1/2] nvme: update enumerations for status codes
In-Reply-To: <20210121090948.8027-1-mgurtovoy@nvidia.com>
References: <20210121090948.8027-1-mgurtovoy@nvidia.com>
Message-ID: <20210121090948.8027-3-mgurtovoy@nvidia.com>

All the updates are mentioned in the ratified NVMe 1.4 spec.

Reviewed-by: Hannes Reinecke <hare at suse.de>
Signed-off-by: Max Gurtovoy <mgurtovoy at nvidia.com>
---
 include/linux/nvme.h | 24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/include/linux/nvme.h b/include/linux/nvme.h
index d92535997687..1c9c34be8194 100644
--- a/include/linux/nvme.h
+++ b/include/linux/nvme.h
@@ -1467,20 +1467,29 @@ enum {
 	NVME_SC_SGL_INVALID_DATA	= 0xf,
 	NVME_SC_SGL_INVALID_METADATA	= 0x10,
 	NVME_SC_SGL_INVALID_TYPE	= 0x11,
-
+	NVME_SC_CMB_INVALID_USE		= 0x12,
+	NVME_SC_PRP_INVALID_OFFSET	= 0x13,
+	NVME_SC_ATOMIC_WU_EXCEEDED	= 0x14,
+	NVME_SC_OP_DENIED		= 0x15,
 	NVME_SC_SGL_INVALID_OFFSET	= 0x16,
-	NVME_SC_SGL_INVALID_SUBTYPE	= 0x17,
-
+	NVME_SC_RESERVED		= 0x17,
+	NVME_SC_HOST_ID_INCONSIST	= 0x18,
+	NVME_SC_KA_TIMEOUT_EXPIRED	= 0x19,
+	NVME_SC_KA_TIMEOUT_INVALID	= 0x1A,
+	NVME_SC_ABORTED_PREEMPT_ABORT	= 0x1B,
 	NVME_SC_SANITIZE_FAILED		= 0x1C,
 	NVME_SC_SANITIZE_IN_PROGRESS	= 0x1D,
-
+	NVME_SC_SGL_INVALID_GRANULARITY	= 0x1E,
+	NVME_SC_CMD_NOT_SUP_CMB_QUEUE	= 0x1F,
 	NVME_SC_NS_WRITE_PROTECTED	= 0x20,
 	NVME_SC_CMD_INTERRUPTED		= 0x21,
+	NVME_SC_TRANSIENT_TR_ERR	= 0x22,
 
 	NVME_SC_LBA_RANGE		= 0x80,
 	NVME_SC_CAP_EXCEEDED		= 0x81,
 	NVME_SC_NS_NOT_READY		= 0x82,
 	NVME_SC_RESERVATION_CONFLICT	= 0x83,
+	NVME_SC_FORMAT_IN_PROGRESS	= 0x84,
 
 	/*
 	 * Command Specific Status:
@@ -1513,8 +1522,15 @@ enum {
 	NVME_SC_NS_NOT_ATTACHED		= 0x11a,
 	NVME_SC_THIN_PROV_NOT_SUPP	= 0x11b,
 	NVME_SC_CTRL_LIST_INVALID	= 0x11c,
+	NVME_SC_SELT_TEST_IN_PROGRESS	= 0x11d,
 	NVME_SC_BP_WRITE_PROHIBITED	= 0x11e,
+	NVME_SC_CTRL_ID_INVALID		= 0x11f,
+	NVME_SC_SEC_CTRL_STATE_INVALID	= 0x120,
+	NVME_SC_CTRL_RES_NUM_INVALID	= 0x121,
+	NVME_SC_RES_ID_INVALID		= 0x122,
 	NVME_SC_PMR_SAN_PROHIBITED	= 0x123,
+	NVME_SC_ANA_GROUP_ID_INVALID	= 0x124,
+	NVME_SC_ANA_ATTACH_FAILED	= 0x125,
 
 	/*
 	 * I/O Command Set Specific - NVM commands:
-- 
2.25.4



From mgurtovoy at nvidia.com  Thu Jan 21 04:09:48 2021
From: mgurtovoy at nvidia.com (Max Gurtovoy)
Date: Thu, 21 Jan 2021 09:09:48 +0000
Subject: [PATCH 2/2] nvme: resync header file with common nvme-cli tool
In-Reply-To: <20210121090948.8027-1-mgurtovoy@nvidia.com>
References: <20210121090948.8027-1-mgurtovoy@nvidia.com>
Message-ID: <20210121090948.8027-4-mgurtovoy@nvidia.com>

Import constant definitions that were added to nvme-cli and were not
added to Linux. This is the first step to align nvme.h files from Linux
kernel include/linux/nvme.h and nvme-cli linux/nvme.h.

Signed-off-by: Max Gurtovoy <mgurtovoy at nvidia.com>
---
 include/linux/nvme.h | 66 ++++++++++++++++++++++++++++++++++----------
 1 file changed, 52 insertions(+), 14 deletions(-)

diff --git a/include/linux/nvme.h b/include/linux/nvme.h
index 1c9c34be8194..5d10c4cf3d33 100644
--- a/include/linux/nvme.h
+++ b/include/linux/nvme.h
@@ -113,18 +113,16 @@ enum {
 	NVME_REG_CMBSZ	= 0x003c,	/* Controller Memory Buffer Size */
 	NVME_REG_BPINFO	= 0x0040,	/* Boot Partition Information */
 	NVME_REG_BPRSEL	= 0x0044,	/* Boot Partition Read Select */
-	NVME_REG_BPMBL	= 0x0048,	/* Boot Partition Memory Buffer
-					 * Location
-					 */
+	NVME_REG_BPMBL	= 0x0048,	/* Boot Partition Memory Buffer Location */
+	NVME_REG_CMBMSC	= 0x0050,	/* Controller Memory Buffer Memory Space Control */
+	NVME_REG_CMBSTS	= 0x0058,	/* Controller Memory Buffer Status */
+
 	NVME_REG_PMRCAP	= 0x0e00,	/* Persistent Memory Capabilities */
 	NVME_REG_PMRCTL	= 0x0e04,	/* Persistent Memory Region Control */
 	NVME_REG_PMRSTS	= 0x0e08,	/* Persistent Memory Region Status */
-	NVME_REG_PMREBS	= 0x0e0c,	/* Persistent Memory Region Elasticity
-					 * Buffer Size
-					 */
-	NVME_REG_PMRSWTP = 0x0e10,	/* Persistent Memory Region Sustained
-					 * Write Throughput
-					 */
+	NVME_REG_PMREBS	= 0x0e0c,	/* Persistent Memory Region Elasticity Buffer Size */
+	NVME_REG_PMRSWTP = 0x0e10,	/* Persistent Memory Region Sustained Write Throughput */
+	NVME_REG_PMRMSC = 0x0e14,	/* Persistent Memory Region Controller Memory Space Control */
 	NVME_REG_DBS	= 0x1000,	/* SQ 0 Tail Doorbell */
 };
 
@@ -138,6 +136,14 @@ enum {
 
 #define NVME_CMB_BIR(cmbloc)	((cmbloc) & 0x7)
 #define NVME_CMB_OFST(cmbloc)	(((cmbloc) >> 12) & 0xfffff)
+#define NVME_CMB_SZ(cmbsz)	(((cmbsz) >> 12) & 0xfffff)
+#define NVME_CMB_SZU(cmbsz)	(((cmbsz) >> 8) & 0xf)
+
+#define NVME_CMB_WDS(cmbsz)	((cmbsz) & 0x10)
+#define NVME_CMB_RDS(cmbsz)	((cmbsz) & 0x8)
+#define NVME_CMB_LISTS(cmbsz)	((cmbsz) & 0x4)
+#define NVME_CMB_CQS(cmbsz)	((cmbsz) & 0x2)
+#define NVME_CMB_SQS(cmbsz)	((cmbsz) & 0x1)
 
 enum {
 	NVME_CMBSZ_SQS		= 1 << 0,
@@ -238,7 +244,10 @@ struct nvme_id_ctrl {
 	__le32			rtd3e;
 	__le32			oaes;
 	__le32			ctratt;
-	__u8			rsvd100[28];
+	__le16			rrls;
+	__u8			rsvd102[9];
+	__u8			cntrltype;
+	char			fguid[16];
 	__le16			crdt1;
 	__le16			crdt2;
 	__le16			crdt3;
@@ -270,12 +279,14 @@ struct nvme_id_ctrl {
 	__le32			sanicap;
 	__le32			hmminds;
 	__le16			hmmaxd;
-	__u8			rsvd338[4];
+	__le16			nsetidmax;
+	__le16			endgidmax;
 	__u8			anatt;
 	__u8			anacap;
 	__le32			anagrpmax;
 	__le32			nanagrpid;
-	__u8			rsvd352[160];
+	__le32			pels;
+	__u8			rsvd356[156];
 	__u8			sqes;
 	__u8			cqes;
 	__le16			maxcmd;
@@ -289,7 +300,7 @@ struct nvme_id_ctrl {
 	__u8			nvscc;
 	__u8			nwpc;
 	__le16			acwu;
-	__u8			rsvd534[2];
+	__le16			ocfs;
 	__le32			sgls;
 	__le32			mnan;
 	__u8			rsvd544[224];
@@ -362,7 +373,10 @@ struct nvme_id_ns {
 	__le16			npdg;
 	__le16			npda;
 	__le16			nows;
-	__u8			rsvd74[18];
+	__le16			mssrl;
+	__le32			mcl;
+	__u8			msrc;
+	__u8			rsvd81[11];
 	__le32			anagrpid;
 	__u8			rsvd96[3];
 	__u8			nsattr;
@@ -404,8 +418,10 @@ enum {
 	NVME_ID_CNS_CTRL		= 0x01,
 	NVME_ID_CNS_NS_ACTIVE_LIST	= 0x02,
 	NVME_ID_CNS_NS_DESC_LIST	= 0x03,
+	NVME_ID_CNS_NVMSET_LIST		= 0x04,
 	NVME_ID_CNS_CS_NS		= 0x05,
 	NVME_ID_CNS_CS_CTRL		= 0x06,
+	NVME_ID_CNS_CS_NS_ACTIVE_LIST	= 0x07,
 	NVME_ID_CNS_NS_PRESENT_LIST	= 0x10,
 	NVME_ID_CNS_NS_PRESENT		= 0x11,
 	NVME_ID_CNS_CTRL_NS_LIST	= 0x12,
@@ -413,6 +429,10 @@ enum {
 	NVME_ID_CNS_SCNDRY_CTRL_LIST	= 0x15,
 	NVME_ID_CNS_NS_GRANULARITY	= 0x16,
 	NVME_ID_CNS_UUID_LIST		= 0x17,
+	NVME_ID_CNS_CSI_NS_PRESENT_LIST	= 0x1a,
+	NVME_ID_CNS_CSI_NS_PRESENT	= 0x1b,
+	NVME_ID_CNS_CSI			= 0x1c,
+
 };
 
 enum {
@@ -673,6 +693,7 @@ enum nvme_opcode {
 	nvme_cmd_resv_report	= 0x0e,
 	nvme_cmd_resv_acquire	= 0x11,
 	nvme_cmd_resv_release	= 0x15,
+	nvme_cmd_copy		= 0x19,
 	nvme_cmd_zone_mgmt_send	= 0x79,
 	nvme_cmd_zone_mgmt_recv	= 0x7a,
 	nvme_cmd_zone_append	= 0x7d,
@@ -1042,6 +1063,7 @@ enum {
 	NVME_FEAT_PLM_WINDOW	= 0x14,
 	NVME_FEAT_HOST_BEHAVIOR	= 0x16,
 	NVME_FEAT_SANITIZE	= 0x17,
+	NVME_FEAT_IOCS_PROFILE	= 0x19,
 	NVME_FEAT_SW_PROGRESS	= 0x80,
 	NVME_FEAT_HOST_ID	= 0x81,
 	NVME_FEAT_RESV_MASK	= 0x82,
@@ -1058,9 +1080,14 @@ enum {
 	NVME_LOG_TELEMETRY_HOST = 0x07,
 	NVME_LOG_TELEMETRY_CTRL = 0x08,
 	NVME_LOG_ENDURANCE_GROUP = 0x09,
+	NVME_LOG_PRELAT_PER_NVMSET	= 0x0a,
+	NVME_LOG_PRELAT_EVENT_AGG	= 0x0b,
 	NVME_LOG_ANA		= 0x0c,
+	NVME_LOG_PERSISTENT_EVENT   = 0x0d,
 	NVME_LOG_DISC		= 0x70,
 	NVME_LOG_RESERVATION	= 0x80,
+	NVME_LOG_SANITIZE	= 0x81,
+	NVME_LOG_ZONE_CHANGED_LIST = 0xbf,
 	NVME_FWACT_REPL		= (0 << 3),
 	NVME_FWACT_REPL_ACTV	= (1 << 3),
 	NVME_FWACT_ACTV		= (2 << 3),
@@ -1300,6 +1327,9 @@ struct nvmf_disc_rsp_page_entry {
 			__u16	pkey;
 			__u8	resv10[246];
 		} rdma;
+		struct tcp {
+			__u8	sectype;
+		} tcp;
 	} tsas;
 };
 
@@ -1532,6 +1562,14 @@ enum {
 	NVME_SC_ANA_GROUP_ID_INVALID	= 0x124,
 	NVME_SC_ANA_ATTACH_FAILED	= 0x125,
 
+	/*
+	 * Command Set Specific - Namespace Types commands:
+	 */
+	NVME_SC_IOCS_NOT_SUPPORTED	= 0x129,
+	NVME_SC_IOCS_NOT_ENABLED	= 0x12a,
+	NVME_SC_IOCS_COMBINATION_REJ	= 0x12b,
+	NVME_SC_INVALID_IOCS		= 0x12c,
+
 	/*
 	 * I/O Command Set Specific - NVM commands:
 	 */
-- 
2.25.4



From mgurtovoy at nvidia.com  Thu Jan 21 04:09:46 2021
From: mgurtovoy at nvidia.com (Max Gurtovoy)
Date: Thu, 21 Jan 2021 09:09:46 +0000
Subject: [PATCH nvme-cli 1/1] align Linux kernel nvme.h to nvme-cli
In-Reply-To: <20210121090948.8027-1-mgurtovoy@nvidia.com>
References: <20210121090948.8027-1-mgurtovoy@nvidia.com>
Message-ID: <20210121090948.8027-2-mgurtovoy@nvidia.com>

This is the first step to align nvme.h files from Linux kernel
include/linux/nvme.h and nvme-cli linux/nvme.h.

Internally divide linux/nvme.h into 2 parts:
 - nvme-cli specific code
 - identical copy of the content of include/linux/nvme.h

The next step might be reducing the first part to be as minimal as
possible and have a version that is in sync with kernel header. In this
way it will be easier to maintain the code and the sync process will be
fast copy/paste to part 2 of the linux/nvme.h file.

Signed-off-by: Max Gurtovoy <mgurtovoy at nvidia.com>
---
 linux/nvme.h                   | 2274 ++++++++++++++++++++------------
 nvme-ioctl.c                   |   12 +-
 nvme-print.c                   |   70 +-
 nvme-print.h                   |    6 +-
 nvme-status.c                  |   14 +-
 nvme.h                         |   23 +
 plugins/shannon/shannon-nvme.c |    4 +-
 plugins/virtium/virtium-nvme.c |    2 +-
 plugins/zns/zns.c              |    6 +-
 9 files changed, 1475 insertions(+), 936 deletions(-)

diff --git a/linux/nvme.h b/linux/nvme.h
index 025f638..85fd4a4 100644
--- a/linux/nvme.h
+++ b/linux/nvme.h
@@ -31,6 +31,13 @@ typedef struct {
 #define __force
 #endif
 
+#ifndef likely
+#define likely(x)   __builtin_expect(!!(x), 1)
+#endif
+#ifndef unlikely
+#define unlikely(x)   __builtin_expect(!!(x), 0)
+#endif
+
 static inline __le16 cpu_to_le16(uint16_t x)
 {
 	return (__force __le16)htole16(x);
@@ -57,161 +64,763 @@ static inline uint64_t le64_to_cpu(__le64 x)
 	return le64toh((__force __u64)x);
 }
 
-/* NQN names in commands fields specified one size */
-#define NVMF_NQN_FIELD_LEN	256
+/******************** nvme-cli specific ********************************/
 
-/* However the max length of a qualified name is another size */
-#define NVMF_NQN_SIZE		223
+#define NVME_DISC_IP_PORT	8009
 
-#define NVMF_TRSVCID_SIZE	32
-#define NVMF_TRADDR_SIZE	256
-#define NVMF_TSAS_SIZE		256
+/* TCP port security type for  Discovery Log Page entry TSAS
+ */
+enum {
+	NVMF_TCP_SECTYPE_NONE	= 0, /* No Security */
+	NVMF_TCP_SECTYPE_TLS	= 1, /* Transport Layer Security */
+};
 
-#define NVME_DISC_SUBSYS_NAME	"nqn.2014-08.org.nvmexpress.discovery"
+/* I/O Command Sets
+ */
+enum {
+	NVME_IOCS_NVM   = 0x00,
+	NVME_IOCS_ZONED = 0x02,
+};
 
-#define NVME_RDMA_IP_PORT	4420
-#define NVME_DISC_IP_PORT	8009
+struct nvme_id_iocs {
+	__le64 iocs[512];
+};
 
-#define NVME_NSID_ALL		0xffffffff
+/* idle and active power scales occupy the last 2 bits of the field */
+#define POWER_SCALE(s) ((s) >> 6)
 
-enum nvme_subsys_type {
-	NVME_NQN_DISC	= 1,		/* Discovery type target subsystem */
-	NVME_NQN_NVME	= 2,		/* NVME type target subsystem */
+#define NVME_MAX_NVMSET		31
+
+struct nvme_nvmset_attr_entry {
+	__le16			id;
+	__le16			endurance_group_id;
+	__u8			rsvd4[4];
+	__le32			random_4k_read_typical;
+	__le32			opt_write_size;
+	__u8			total_nvmset_cap[16];
+	__u8			unalloc_nvmset_cap[16];
+	__u8			rsvd48[80];
 };
 
-/* Address Family codes for Discovery Log Page entry ADRFAM field */
-enum {
-	NVMF_ADDR_FAMILY_PCI	= 0,	/* PCIe */
-	NVMF_ADDR_FAMILY_IP4	= 1,	/* IP4 */
-	NVMF_ADDR_FAMILY_IP6	= 2,	/* IP6 */
-	NVMF_ADDR_FAMILY_IB	= 3,	/* InfiniBand */
-	NVMF_ADDR_FAMILY_FC	= 4,	/* Fibre Channel */
-	NVMF_ADDR_FAMILY_LOOP	= 254,	/* Reserved for host usage */
-	NVMF_ADDR_FAMILY_MAX,
+struct nvme_id_nvmset {
+	__u8				nid;
+	__u8				rsvd1[127];
+	struct nvme_nvmset_attr_entry	ent[NVME_MAX_NVMSET];
 };
 
-/* Transport Type codes for Discovery Log Page entry TRTYPE field */
-enum {
-	NVMF_TRTYPE_RDMA	= 1,	/* RDMA */
-	NVMF_TRTYPE_FC		= 2,	/* Fibre Channel */
-	NVMF_TRTYPE_TCP		= 3,	/* TCP */
-	NVMF_TRTYPE_LOOP	= 254,	/* Reserved for host usage */
-	NVMF_TRTYPE_MAX,
+struct nvme_id_ns_granularity_list_entry {
+	__le64			namespace_size_granularity;
+	__le64			namespace_capacity_granularity;
 };
 
-/* Transport Requirements codes for Discovery Log Page entry TREQ field */
-enum {
-	NVMF_TREQ_NOT_SPECIFIED	= 0,		/* Not specified */
-	NVMF_TREQ_REQUIRED	= 1,		/* Required */
-	NVMF_TREQ_NOT_REQUIRED	= 2,		/* Not Required */
-	NVMF_TREQ_DISABLE_SQFLOW = (1 << 2),	/* SQ flow control disable supported */
+struct nvme_id_ns_granularity_list {
+	__le32			attributes;
+	__u8			num_descriptors;
+	__u8			rsvd[27];
+	struct nvme_id_ns_granularity_list_entry entry[16];
 };
 
-/* RDMA QP Service Type codes for Discovery Log Page entry TSAS
- * RDMA_QPTYPE field
- */
-enum {
-	NVMF_RDMA_QPTYPE_CONNECTED	= 1, /* Reliable Connected */
-	NVMF_RDMA_QPTYPE_DATAGRAM	= 2, /* Reliable Datagram */
+#define NVME_MAX_UUID_ENTRIES	128
+struct nvme_id_uuid_list_entry {
+	__u8			header;
+	__u8			rsvd1[15];
+	__u8			uuid[16];
 };
 
-/* RDMA QP Service Type codes for Discovery Log Page entry TSAS
- * RDMA_QPTYPE field
- */
-enum {
-	NVMF_RDMA_PRTYPE_NOT_SPECIFIED	= 1, /* No Provider Specified */
-	NVMF_RDMA_PRTYPE_IB		= 2, /* InfiniBand */
-	NVMF_RDMA_PRTYPE_ROCE		= 3, /* InfiniBand RoCE */
-	NVMF_RDMA_PRTYPE_ROCEV2		= 4, /* InfiniBand RoCEV2 */
-	NVMF_RDMA_PRTYPE_IWARP		= 5, /* IWARP */
+struct nvme_id_uuid_list {
+	struct nvme_id_uuid_list_entry	entry[NVME_MAX_UUID_ENTRIES];
 };
 
-/* RDMA Connection Management Service Type codes for Discovery Log Page
- * entry TSAS RDMA_CMS field
+/**
+ * struct nvme_telemetry_log_page_hdr - structure for telemetry log page
+ * @lpi: Log page identifier
+ * @iee_oui: IEEE OUI Identifier
+ * @dalb1: Data area 1 last block
+ * @dalb2: Data area 2 last block
+ * @dalb3: Data area 3 last block
+ * @ctrlavail: Controller initiated data available
+ * @ctrldgn: Controller initiated telemetry Data Generation Number
+ * @rsnident: Reason Identifier
+ * @telemetry_dataarea: Contains telemetry data block
+ *
+ * This structure can be used for both telemetry host-initiated log page
+ * and controller-initiated log page.
  */
-enum {
-	NVMF_RDMA_CMS_RDMA_CM	= 1, /* Sockets based endpoint addressing */
+struct nvme_telemetry_log_page_hdr {
+	__u8	lpi;
+	__u8	rsvd[4];
+	__u8	iee_oui[3];
+	__le16	dalb1;
+	__le16	dalb2;
+	__le16	dalb3;
+	__u8	rsvd1[368];
+	__u8	ctrlavail;
+	__u8	ctrldgn;
+	__u8	rsnident[128];
+	__u8	telemetry_dataarea[0];
 };
 
-/* TCP port security type for  Discovery Log Page entry TSAS
- */
-enum {
-	NVMF_TCP_SECTYPE_NONE	= 0, /* No Security */
-	NVMF_TCP_SECTYPE_TLS	= 1, /* Transport Layer Security */
+struct nvme_endurance_group_log {
+	__u8	critical_warning;
+	__u8	rsvd1[2];
+	__u8	avl_spare;
+	__u8	avl_spare_threshold;
+	__u8	percent_used;
+	__u8	rsvd6[26];
+	__u8	endurance_estimate[16];
+	__u8	data_units_read[16];
+	__u8	data_units_written[16];
+	__u8	media_units_written[16];
+	__u8	host_read_cmds[16];
+	__u8	host_write_cmds[16];
+	__u8	media_data_integrity_err[16];
+	__u8	num_err_info_log_entries[16];
+	__u8	rsvd160[352];
 };
 
-/* I/O Command Sets
- */
+struct nvme_self_test_res {
+	__u8 			dsts;
+	__u8			seg;
+	__u8			vdi;
+	__u8			rsvd3;
+	__le64			poh;
+	__le32			nsid;
+	__le64			flba;
+	__u8			sct;
+	__u8			sc;
+	__u8			vs[2];
+} __attribute__((packed));
+
 enum {
-	NVME_IOCS_NVM   = 0x00,
-	NVME_IOCS_ZONED = 0x02,
+	NVME_ST_CODE_SHIFT    		= 4,
+	NVME_ST_CODE_SHORT_OP 		= 0x1,
+	NVME_ST_CODE_EXT_OP   		= 0x2,
+	NVME_ST_CODE_VS	      		= 0xe,
+	NVME_ST_RES_MASK      		= 0xf,
+	NVME_ST_RES_NO_ERR    		= 0x0,
+	NVME_ST_RES_ABORTED   		= 0x1,
+	NVME_ST_RES_CLR	      		= 0x2,
+	NVME_ST_RES_NS_REMOVED		= 0x3,
+	NVME_ST_RES_ABORTED_FORMAT	= 0x4,
+	NVME_ST_RES_FATAL_ERR		= 0x5,
+	NVME_ST_RES_UNKNOWN_SEG_FAIL	= 0x6,
+	NVME_ST_RES_KNOWN_SEG_FAIL	= 0x7,
+	NVME_ST_RES_ABORTED_UNKNOWN	= 0x8,
+	NVME_ST_RES_ABORTED_SANITIZE	= 0x9,
+	NVME_ST_RES_NOT_USED		= 0xf,
+	NVME_ST_VALID_NSID		= 1 << 0,
+	NVME_ST_VALID_FLBA		= 1 << 1,
+	NVME_ST_VALID_SCT		= 1 << 2,
+	NVME_ST_VALID_SC		= 1 << 3,
+	NVME_ST_REPORTS			= 20,
 };
 
-#define NVME_AQ_DEPTH		32
-#define NVME_NR_AEN_COMMANDS	1
-#define NVME_AQ_BLK_MQ_DEPTH	(NVME_AQ_DEPTH - NVME_NR_AEN_COMMANDS)
-
-/*
- * Subtract one to leave an empty queue entry for 'Full Queue' condition. See
- * NVM-Express 1.2 specification, section 4.1.2.
- */
-#define NVME_AQ_MQ_TAG_DEPTH	(NVME_AQ_BLK_MQ_DEPTH - 1)
+struct nvme_self_test_log {
+	__u8                      crnt_dev_selftest_oprn;
+	__u8                      crnt_dev_selftest_compln;
+	__u8                      rsvd[2];
+	struct nvme_self_test_res result[20];
+} __attribute__((packed));
 
-enum {
-	NVME_REG_CAP	= 0x0000,	/* Controller Capabilities */
-	NVME_REG_VS	= 0x0008,	/* Version */
-	NVME_REG_INTMS	= 0x000c,	/* Interrupt Mask Set */
-	NVME_REG_INTMC	= 0x0010,	/* Interrupt Mask Clear */
-	NVME_REG_CC	= 0x0014,	/* Controller Configuration */
-	NVME_REG_CSTS	= 0x001c,	/* Controller Status */
-	NVME_REG_NSSR	= 0x0020,	/* NVM Subsystem Reset */
-	NVME_REG_AQA	= 0x0024,	/* Admin Queue Attributes */
-	NVME_REG_ASQ	= 0x0028,	/* Admin SQ Base Address */
-	NVME_REG_ACQ	= 0x0030,	/* Admin CQ Base Address */
-	NVME_REG_CMBLOC = 0x0038,	/* Controller Memory Buffer Location */
-	NVME_REG_CMBSZ	= 0x003c,	/* Controller Memory Buffer Size */
-	NVME_REG_BPINFO	= 0x0040,	/* Boot Partition Information */
-	NVME_REG_BPRSEL	= 0x0044,	/* Boot Partition Read Select */
-	NVME_REG_BPMBL	= 0x0048,	/* Boot Partition Memory Buffer Location */
-	NVME_REG_CMBMSC	= 0x0050,	/* Controller Memory Buffer Memory Space Control */
-	NVME_REG_CMBSTS	= 0x0058,	/* Controller Memory Buffer Status */
-	NVME_REG_PMRCAP = 0x0e00,	/* Persistent Memory Capabilities */
-	NVME_REG_PMRCTL = 0x0e04,	/* Persistent Memory Region Control */
-	NVME_REG_PMRSTS = 0x0e08,	/* Persistent Memory Region Status */
-	NVME_REG_PMREBS = 0x0e0c,	/* Persistent Memory Region Elasticity Buffer Size */
-	NVME_REG_PMRSWTP= 0x0e10,	/* Persistent Memory Region Sustained Write Throughput */
-	NVME_REG_PMRMSC = 0x0e14,	/* Persistent Memory Region Controller Memory Space Control */
-	NVME_REG_DBS	= 0x1000,	/* SQ 0 Tail Doorbell */
+struct nvme_lba_status_desc {
+	__u64 dslba;
+	__u32 nlb;
+	__u8 rsvd_12;
+	__u8 status;
+	__u8 rsvd_15_14[2];
 };
 
-#define NVME_CAP_MQES(cap)	((cap) & 0xffff)
-#define NVME_CAP_TIMEOUT(cap)	(((cap) >> 24) & 0xff)
-#define NVME_CAP_STRIDE(cap)	(((cap) >> 32) & 0xf)
-#define NVME_CAP_NSSRC(cap)	(((cap) >> 36) & 0x1)
-#define NVME_CAP_MPSMIN(cap)	(((cap) >> 48) & 0xf)
-#define NVME_CAP_MPSMAX(cap)	(((cap) >> 52) & 0xf)
+struct nvme_lba_status {
+	__u32 nlsd;
+	__u8 cmpc;
+	__u8 rsvd_7_5[3];
+	struct nvme_lba_status_desc descs[0];
+};
 
-#define NVME_CMB_BIR(cmbloc)	((cmbloc) & 0x7)
-#define NVME_CMB_OFST(cmbloc)	(((cmbloc) >> 12) & 0xfffff)
-#define NVME_CMB_SZ(cmbsz)	(((cmbsz) >> 12) & 0xfffff)
-#define NVME_CMB_SZU(cmbsz)	(((cmbsz) >> 8) & 0xf)
+#define NVME_MAX_CHANGED_NAMESPACES     1024
 
-#define NVME_CMB_WDS(cmbsz)	((cmbsz) & 0x10)
-#define NVME_CMB_RDS(cmbsz)	((cmbsz) & 0x8)
-#define NVME_CMB_LISTS(cmbsz)	((cmbsz) & 0x4)
-#define NVME_CMB_CQS(cmbsz)	((cmbsz) & 0x2)
-#define NVME_CMB_SQS(cmbsz)	((cmbsz) & 0x1)
+struct nvme_changed_ns_list_log {
+	__le32			log[NVME_MAX_CHANGED_NAMESPACES];
+};
 
-/*
- * Submission and Completion Queue Entry Sizes for the NVM command set.
+/* persistent event type 02h */
+struct nvme_fw_commit_event {
+    __le64	old_fw_rev;
+    __le64 	new_fw_rev;
+    __u8 	fw_commit_action;
+    __u8 	fw_slot;
+    __u8 	sct_fw;
+    __u8 	sc_fw;
+    __le16 	vndr_assign_fw_commit_rc;
+} __attribute__((packed));
+
+/* persistent event type 03h */
+struct nvme_time_stamp_change_event {
+    __le64 	previous_timestamp;
+    __le64 	ml_secs_since_reset;
+};
+
+/* persistent event type 04h */
+struct nvme_power_on_reset_info_list {
+    __le16   cid;
+    __u8     fw_act;
+    __u8     op_in_prog;
+    __u8     rsvd4[12];
+    __le32   ctrl_power_cycle;
+    __le64   power_on_ml_seconds;
+    __le64   ctrl_time_stamp;
+} __attribute__((packed));
+
+/* persistent event type 05h */
+struct nvme_nss_hw_err_event {
+    __le16 	nss_hw_err_event_code;
+    __u8 	rsvd2[2];
+    __u8 	*add_hw_err_info;
+};
+
+/* persistent event type 06h */
+struct nvme_change_ns_event {
+	__le32	nsmgt_cdw10;
+	__u8	rsvd4[4];
+	__le64	nsze;
+	__u8	nscap[16];
+	__u8	flbas;
+	__u8	dps;
+	__u8	nmic;
+	__u8	rsvd35;
+	__le32	ana_grp_id;
+	__le16	nvmset_id;
+	__le16	rsvd42;
+	__le32	nsid;
+};
+
+/* persistent event type 07h */
+struct nvme_format_nvm_start_event {
+    __le32 	nsid;
+    __u8 	fna;
+    __u8 	rsvd5[3];
+    __le32 	format_nvm_cdw10;
+};
+
+/* persistent event type 08h */
+struct nvme_format_nvm_compln_event {
+    __le32 	nsid;
+    __u8 	smallest_fpi;
+    __u8 	format_nvm_status;
+    __le16 	compln_info;
+    __le32 	status_field;
+};
+
+/* persistent event type 09h */
+struct nvme_sanitize_start_event {
+    __le32 	sani_cap;
+    __le32 	sani_cdw10;
+    __le32 	sani_cdw11;
+};
+
+/* persistent event type 0Ah */
+struct nvme_sanitize_compln_event {
+    __le16 	sani_prog;
+    __le16 	sani_status;
+    __le16 	cmpln_info;
+	__u8 	rsvd6[2];
+};
+
+/* persistent event type 0Dh */
+struct nvme_thermal_exc_event {
+    __u8 	over_temp;
+    __u8 	threshold;
+};
+
+/* persistent event entry head */
+struct nvme_persistent_event_entry_head {
+	__u8	etype;
+	__u8	etype_rev;
+	__u8	ehl;
+	__u8	rsvd3;
+	__le16	ctrl_id;
+	__le64	etimestamp;
+	__u8	rsvd14[6];
+	__le16	vsil;
+	__le16	el;
+} __attribute__((packed));
+
+/* persistent event log head */
+struct nvme_persistent_event_log_head {
+	__u8	log_id;
+	__u8	rsvd1[3];
+	__le32	tnev;
+	__le64	tll;
+	__u8	log_rev;
+	__u8	rsvd17;
+	__le16	head_len;
+	__le64	timestamp;
+	__u8	poh[16];
+	__le64	pcc;
+	__le16	vid;
+	__le16	ssvid;
+	__u8	sn[20];
+	__u8	mn[40];
+	__u8	subnqn[256];
+	__u8    rsvd372[108];
+	__u8	supp_event_bm[32];
+} __attribute__((packed));
+
+enum nvme_persistent_event_types {
+    NVME_SMART_HEALTH_EVENT         = 0x01,
+    NVME_FW_COMMIT_EVENT            = 0x02,
+    NVME_TIMESTAMP_EVENT            = 0x03,
+    NVME_POWER_ON_RESET_EVENT       = 0x04,
+    NVME_NSS_HW_ERROR_EVENT         = 0x05,
+    NVME_CHANGE_NS_EVENT            = 0x06,
+    NVME_FORMAT_START_EVENT         = 0x07,
+    NVME_FORMAT_COMPLETION_EVENT    = 0x08,
+    NVME_SANITIZE_START_EVENT       = 0x09,
+    NVME_SANITIZE_COMPLETION_EVENT  = 0x0a,
+    NVME_THERMAL_EXCURSION_EVENT    = 0x0d
+};
+
+enum nvme_persistent_event_log_actions {
+	NVME_PEVENT_LOG_READ				= 0x0,
+	NVME_PEVENT_LOG_EST_CTX_AND_READ	= 0x1,
+	NVME_PEVENT_LOG_RELEASE_CTX			= 0x2,
+};
+
+struct nvme_predlat_event_agg_log_page {
+	__le64	num_entries;
+	__le16	entries[];
+};
+
+struct nvme_predlat_per_nvmset_log_page {
+	__u8	status;
+	__u8	rsvd1;
+	__le16	event_type;
+	__u8	rsvd4[28];
+	__le64	dtwin_rtyp;
+	__le64	dtwin_wtyp;
+	__le64	dtwin_timemax;
+	__le64	ndwin_timemin_high;
+	__le64	ndwin_timemin_low;
+	__u8	rsvd72[56];
+	__le64	dtwin_restimate;
+	__le64	dtwin_westimate;
+	__le64	dtwin_testimate;
+	__u8	rsvd152[360];
+};
+
+/* Predictable Latency Mode - Deterministic Threshold Configuration Data */
+struct nvme_plm_config {
+	__le16	enable_event;
+	__u8	rsvd2[30];
+	__le64	dtwin_reads_thresh;
+	__le64	dtwin_writes_thresh;
+	__le64	dtwin_time_thresh;
+	__u8	rsvd56[456];
+};
+
+struct nvme_reservation_status_ext {
+	__le32	gen;
+	__u8	rtype;
+	__u8	regctl[2];
+	__u8	resv5[2];
+	__u8	ptpls;
+	__u8	resv10[14];
+	__u8	resv24[40];
+	struct {
+		__le16	cntlid;
+		__u8	rcsts;
+		__u8	resv3[5];
+		__le64	rkey;
+		__u8	hostid[16];
+		__u8	resv32[32];
+	} regctl_eds[];
+};
+
+enum {
+	NVME_RW_DEAC			= 1 << 9,
+};
+
+struct nvme_copy_range {
+	__u8			rsvd0[8];
+	__le64			slba;
+	__le16			nlb;
+	__u8			rsvd18[6];
+	__le32			eilbrt;
+	__le16			elbatm;
+	__le16			elbat;
+};
+
+enum {
+	NVME_NO_LOG_LSP       = 0x0,
+	NVME_NO_LOG_LPO       = 0x0,
+	NVME_LOG_ANA_LSP_RGO  = 0x1,
+	NVME_TELEM_LSP_CREATE = 0x1,
+};
+
+/* Sanitize and Sanitize Monitor/Log */
+enum {
+	/* Sanitize */
+	NVME_SANITIZE_NO_DEALLOC	= 0x00000200,
+	NVME_SANITIZE_OIPBP		= 0x00000100,
+	NVME_SANITIZE_OWPASS_SHIFT	= 0x00000004,
+	NVME_SANITIZE_AUSE		= 0x00000008,
+	NVME_SANITIZE_ACT_CRYPTO_ERASE	= 0x00000004,
+	NVME_SANITIZE_ACT_OVERWRITE	= 0x00000003,
+	NVME_SANITIZE_ACT_BLOCK_ERASE	= 0x00000002,
+	NVME_SANITIZE_ACT_EXIT		= 0x00000001,
+
+	/* Sanitize Monitor/Log */
+	NVME_SANITIZE_LOG_DATA_LEN		= 0x0014,
+	NVME_SANITIZE_LOG_GLOBAL_DATA_ERASED	= 0x0100,
+	NVME_SANITIZE_LOG_NUM_CMPLTED_PASS_MASK	= 0x00F8,
+	NVME_SANITIZE_LOG_STATUS_MASK		= 0x0007,
+	NVME_SANITIZE_LOG_NEVER_SANITIZED	= 0x0000,
+	NVME_SANITIZE_LOG_COMPLETED_SUCCESS	= 0x0001,
+	NVME_SANITIZE_LOG_IN_PROGESS		= 0x0002,
+	NVME_SANITIZE_LOG_COMPLETED_FAILED	= 0x0003,
+	NVME_SANITIZE_LOG_ND_COMPLETED_SUCCESS	= 0x0004,
+};
+
+/* Sanitize Log Page */
+struct nvme_sanitize_log_page {
+	__le16			progress;
+	__le16			status;
+	__le32			cdw10_info;
+	__le32			est_ovrwrt_time;
+	__le32			est_blk_erase_time;
+	__le32			est_crypto_erase_time;
+	__le32			est_ovrwrt_time_with_no_deallocate;
+	__le32			est_blk_erase_time_with_no_deallocate;
+	__le32			est_crypto_erase_time_with_no_deallocate;
+};
+
+struct nvme_effects_log_page {
+	__le32 acs[256];
+	__le32 iocs[256];
+	__u8   resv[2048];
+};
+
+struct nvme_error_log_page {
+	__le64	error_count;
+	__le16	sqid;
+	__le16	cmdid;
+	__le16	status_field;
+	__le16	parm_error_location;
+	__le64	lba;
+	__le32	nsid;
+	__u8	vs;
+	__u8	trtype;
+	__u8	resv[2];
+	__le64	cs;
+	__le16	trtype_spec_info;
+	__u8	resv2[22];
+};
+
+struct nvme_firmware_log_page {
+	__u8	afi;
+	__u8	resv[7];
+	__u64	frs[7];
+	__u8	resv2[448];
+};
+
+struct nvme_host_mem_buffer {
+	__u32			hsize;
+	__u32			hmdlal;
+	__u32			hmdlau;
+	__u32			hmdlec;
+	__u8			rsvd16[4080];
+};
+
+struct nvme_auto_pst {
+	__u32	data;
+	__u32	rsvd32;
+};
+
+struct nvme_timestamp {
+	__u8 timestamp[6];
+	__u8 attr;
+	__u8 rsvd;
+};
+
+struct nvme_controller_list {
+	__le16 num;
+	__le16 identifier[2047];
+};
+
+struct nvme_secondary_controller_entry {
+	__le16 scid;	/* Secondary Controller Identifier */
+	__le16 pcid;	/* Primary Controller Identifier */
+	__u8   scs;	/* Secondary Controller State */
+	__u8   rsvd5[3];
+	__le16 vfn;	/* Virtual Function Number */
+	__le16 nvq;	/* Number of VQ Flexible Resources Assigned */
+	__le16 nvi;	/* Number of VI Flexible Resources Assigned */
+	__u8   rsvd14[18];
+};
+
+struct nvme_secondary_controllers_list {
+	__u8   num;
+	__u8   rsvd[31];
+	struct nvme_secondary_controller_entry sc_entry[127];
+};
+
+struct nvme_bar_cap {
+	__u16	mqes;
+	__u8	ams_cqr;
+	__u8	to;
+	__u16	bps_css_nssrs_dstrd;
+	__u8	mpsmax_mpsmin;
+	__u8	rsvd_cmbs_pmrs;
+};
+
+enum {
+	NVME_SCT_GENERIC		= 0x0,
+	NVME_SCT_CMD_SPECIFIC		= 0x1,
+	NVME_SCT_MEDIA			= 0x2,
+};
+
+/**
+ * struct nvme_zns_id_ctrl -
+ * @zasl:
+ */
+struct nvme_zns_id_ctrl {
+	__u8	zasl;
+	__u8	rsvd1[4095];
+};
+
+#define NVME_ZNS_CHANGED_ZONES_MAX	511
+
+/**
+ * struct nvme_zns_changed_zone_log - ZNS Changed Zone List log
+ * @nrzid:
+ * @zid:
+ */
+struct nvme_zns_changed_zone_log {
+	__le16		nrzid;
+	__u8		rsvd2[6];
+	__le64		zid[NVME_ZNS_CHANGED_ZONES_MAX];
+};
+
+/**
+ * enum nvme_zns_za -
+ */
+enum nvme_zns_za {
+	NVME_ZNS_ZA_ZFC			= 1 << 0,
+	NVME_ZNS_ZA_FZR			= 1 << 1,
+	NVME_ZNS_ZA_RZR			= 1 << 2,
+	NVME_ZNS_ZA_ZDEV		= 1 << 7,
+};
+
+/**
+ * enum nvme_zns_zs -
+ */
+enum nvme_zns_zs {
+	NVME_ZNS_ZS_EMPTY		= 0x1,
+	NVME_ZNS_ZS_IMPL_OPEN		= 0x2,
+	NVME_ZNS_ZS_EXPL_OPEN		= 0x3,
+	NVME_ZNS_ZS_CLOSED		= 0x4,
+	NVME_ZNS_ZS_READ_ONLY		= 0xd,
+	NVME_ZNS_ZS_FULL		= 0xe,
+	NVME_ZNS_ZS_OFFLINE		= 0xf,
+};
+
+enum nvme_zns_send_action {
+	NVME_ZNS_ZSA_CLOSE		= 0x1,
+	NVME_ZNS_ZSA_FINISH		= 0x2,
+	NVME_ZNS_ZSA_OPEN		= 0x3,
+	NVME_ZNS_ZSA_RESET		= 0x4,
+	NVME_ZNS_ZSA_OFFLINE		= 0x5,
+	NVME_ZNS_ZSA_SET_DESC_EXT	= 0x10,
+};
+
+enum nvme_zns_recv_action {
+	NVME_ZNS_ZRA_REPORT_ZONES		= 0x0,
+	NVME_ZNS_ZRA_EXTENDED_REPORT_ZONES	= 0x1,
+};
+
+enum nvme_zns_report_options {
+	NVME_ZNS_ZRAS_REPORT_ALL		= 0x0,
+	NVME_ZNS_ZRAS_REPORT_EMPTY		= 0x1,
+	NVME_ZNS_ZRAS_REPORT_IMPL_OPENED	= 0x2,
+	NVME_ZNS_ZRAS_REPORT_EXPL_OPENED	= 0x3,
+	NVME_ZNS_ZRAS_REPORT_CLOSED		= 0x4,
+	NVME_ZNS_ZRAS_REPORT_FULL		= 0x5,
+	NVME_ZNS_ZRAS_REPORT_READ_ONLY		= 0x6,
+	NVME_ZNS_ZRAS_REPORT_OFFLINE		= 0x7,
+};
+
+/******************** nvme-cli specific end ****************************/
+
+/*
+ * Below is the content from Linux include/linux/nvme.h.
+ * Please don't add nothing to this section unless you intend to sync it with
+ * Linux.
+ * Needed changes that are relevant to both Linux and nvme-cli will go through
+ * Linux and then will be synced in nvme-cli.
+ * Needed changes for nvme-cli can go above this comment.
+ */
+
+/******************** include/linux/nvme.h. ********************************/
+
+/* NQN names in commands fields specified one size */
+#define NVMF_NQN_FIELD_LEN	256
+
+/* However the max length of a qualified name is another size */
+#define NVMF_NQN_SIZE		223
+
+#define NVMF_TRSVCID_SIZE	32
+#define NVMF_TRADDR_SIZE	256
+#define NVMF_TSAS_SIZE		256
+
+#define NVME_DISC_SUBSYS_NAME	"nqn.2014-08.org.nvmexpress.discovery"
+
+#define NVME_RDMA_IP_PORT	4420
+
+#define NVME_NSID_ALL		0xffffffff
+
+enum nvme_subsys_type {
+	NVME_NQN_DISC	= 1,		/* Discovery type target subsystem */
+	NVME_NQN_NVME	= 2,		/* NVME type target subsystem */
+};
+
+/* Address Family codes for Discovery Log Page entry ADRFAM field */
+enum {
+	NVMF_ADDR_FAMILY_PCI	= 0,	/* PCIe */
+	NVMF_ADDR_FAMILY_IP4	= 1,	/* IP4 */
+	NVMF_ADDR_FAMILY_IP6	= 2,	/* IP6 */
+	NVMF_ADDR_FAMILY_IB	= 3,	/* InfiniBand */
+	NVMF_ADDR_FAMILY_FC	= 4,	/* Fibre Channel */
+	NVMF_ADDR_FAMILY_LOOP	= 254,	/* Reserved for host usage */
+	NVMF_ADDR_FAMILY_MAX,
+};
+
+/* Transport Type codes for Discovery Log Page entry TRTYPE field */
+enum {
+	NVMF_TRTYPE_RDMA	= 1,	/* RDMA */
+	NVMF_TRTYPE_FC		= 2,	/* Fibre Channel */
+	NVMF_TRTYPE_TCP		= 3,	/* TCP/IP */
+	NVMF_TRTYPE_LOOP	= 254,	/* Reserved for host usage */
+	NVMF_TRTYPE_MAX,
+};
+
+/* Transport Requirements codes for Discovery Log Page entry TREQ field */
+enum {
+	NVMF_TREQ_NOT_SPECIFIED	= 0,		/* Not specified */
+	NVMF_TREQ_REQUIRED	= 1,		/* Required */
+	NVMF_TREQ_NOT_REQUIRED	= 2,		/* Not Required */
+#define NVME_TREQ_SECURE_CHANNEL_MASK \
+	(NVMF_TREQ_REQUIRED | NVMF_TREQ_NOT_REQUIRED)
+
+	NVMF_TREQ_DISABLE_SQFLOW = (1 << 2),	/* Supports SQ flow control disable */
+};
+
+/* RDMA QP Service Type codes for Discovery Log Page entry TSAS
+ * RDMA_QPTYPE field
+ */
+enum {
+	NVMF_RDMA_QPTYPE_CONNECTED	= 1, /* Reliable Connected */
+	NVMF_RDMA_QPTYPE_DATAGRAM	= 2, /* Reliable Datagram */
+};
+
+/* RDMA QP Service Type codes for Discovery Log Page entry TSAS
+ * RDMA_QPTYPE field
+ */
+enum {
+	NVMF_RDMA_PRTYPE_NOT_SPECIFIED	= 1, /* No Provider Specified */
+	NVMF_RDMA_PRTYPE_IB		= 2, /* InfiniBand */
+	NVMF_RDMA_PRTYPE_ROCE		= 3, /* InfiniBand RoCE */
+	NVMF_RDMA_PRTYPE_ROCEV2		= 4, /* InfiniBand RoCEV2 */
+	NVMF_RDMA_PRTYPE_IWARP		= 5, /* IWARP */
+};
+
+/* RDMA Connection Management Service Type codes for Discovery Log Page
+ * entry TSAS RDMA_CMS field
+ */
+enum {
+	NVMF_RDMA_CMS_RDMA_CM	= 1, /* Sockets based endpoint addressing */
+};
+
+#define NVME_AQ_DEPTH		32
+#define NVME_NR_AEN_COMMANDS	1
+#define NVME_AQ_BLK_MQ_DEPTH	(NVME_AQ_DEPTH - NVME_NR_AEN_COMMANDS)
+
+/*
+ * Subtract one to leave an empty queue entry for 'Full Queue' condition. See
+ * NVM-Express 1.2 specification, section 4.1.2.
+ */
+#define NVME_AQ_MQ_TAG_DEPTH	(NVME_AQ_BLK_MQ_DEPTH - 1)
+
+enum {
+	NVME_REG_CAP	= 0x0000,	/* Controller Capabilities */
+	NVME_REG_VS	= 0x0008,	/* Version */
+	NVME_REG_INTMS	= 0x000c,	/* Interrupt Mask Set */
+	NVME_REG_INTMC	= 0x0010,	/* Interrupt Mask Clear */
+	NVME_REG_CC	= 0x0014,	/* Controller Configuration */
+	NVME_REG_CSTS	= 0x001c,	/* Controller Status */
+	NVME_REG_NSSR	= 0x0020,	/* NVM Subsystem Reset */
+	NVME_REG_AQA	= 0x0024,	/* Admin Queue Attributes */
+	NVME_REG_ASQ	= 0x0028,	/* Admin SQ Base Address */
+	NVME_REG_ACQ	= 0x0030,	/* Admin CQ Base Address */
+	NVME_REG_CMBLOC	= 0x0038,	/* Controller Memory Buffer Location */
+	NVME_REG_CMBSZ	= 0x003c,	/* Controller Memory Buffer Size */
+	NVME_REG_BPINFO	= 0x0040,	/* Boot Partition Information */
+	NVME_REG_BPRSEL	= 0x0044,	/* Boot Partition Read Select */
+	NVME_REG_BPMBL	= 0x0048,	/* Boot Partition Memory Buffer Location */
+	NVME_REG_CMBMSC	= 0x0050,	/* Controller Memory Buffer Memory Space Control */
+	NVME_REG_CMBSTS	= 0x0058,	/* Controller Memory Buffer Status */
+
+	NVME_REG_PMRCAP	= 0x0e00,	/* Persistent Memory Capabilities */
+	NVME_REG_PMRCTL	= 0x0e04,	/* Persistent Memory Region Control */
+	NVME_REG_PMRSTS	= 0x0e08,	/* Persistent Memory Region Status */
+	NVME_REG_PMREBS	= 0x0e0c,	/* Persistent Memory Region Elasticity Buffer Size */
+	NVME_REG_PMRSWTP = 0x0e10,	/* Persistent Memory Region Sustained Write Throughput */
+	NVME_REG_PMRMSC = 0x0e14,	/* Persistent Memory Region Controller Memory Space Control */
+	NVME_REG_DBS	= 0x1000,	/* SQ 0 Tail Doorbell */
+};
+
+#define NVME_CAP_MQES(cap)	((cap) & 0xffff)
+#define NVME_CAP_TIMEOUT(cap)	(((cap) >> 24) & 0xff)
+#define NVME_CAP_STRIDE(cap)	(((cap) >> 32) & 0xf)
+#define NVME_CAP_NSSRC(cap)	(((cap) >> 36) & 0x1)
+#define NVME_CAP_CSS(cap)	(((cap) >> 37) & 0xff)
+#define NVME_CAP_MPSMIN(cap)	(((cap) >> 48) & 0xf)
+#define NVME_CAP_MPSMAX(cap)	(((cap) >> 52) & 0xf)
+
+#define NVME_CMB_BIR(cmbloc)	((cmbloc) & 0x7)
+#define NVME_CMB_OFST(cmbloc)	(((cmbloc) >> 12) & 0xfffff)
+#define NVME_CMB_SZ(cmbsz)	(((cmbsz) >> 12) & 0xfffff)
+#define NVME_CMB_SZU(cmbsz)	(((cmbsz) >> 8) & 0xf)
+
+#define NVME_CMB_WDS(cmbsz)	((cmbsz) & 0x10)
+#define NVME_CMB_RDS(cmbsz)	((cmbsz) & 0x8)
+#define NVME_CMB_LISTS(cmbsz)	((cmbsz) & 0x4)
+#define NVME_CMB_CQS(cmbsz)	((cmbsz) & 0x2)
+#define NVME_CMB_SQS(cmbsz)	((cmbsz) & 0x1)
+
+enum {
+	NVME_CMBSZ_SQS		= 1 << 0,
+	NVME_CMBSZ_CQS		= 1 << 1,
+	NVME_CMBSZ_LISTS	= 1 << 2,
+	NVME_CMBSZ_RDS		= 1 << 3,
+	NVME_CMBSZ_WDS		= 1 << 4,
+
+	NVME_CMBSZ_SZ_SHIFT	= 12,
+	NVME_CMBSZ_SZ_MASK	= 0xfffff,
+
+	NVME_CMBSZ_SZU_SHIFT	= 8,
+	NVME_CMBSZ_SZU_MASK	= 0xf,
+};
+
+/*
+ * Submission and Completion Queue Entry Sizes for the NVM command set.
  * (In bytes and specified as a power of two (2^n)).
  */
+#define NVME_ADM_SQES       6
 #define NVME_NVM_IOSQES		6
 #define NVME_NVM_IOCQES		4
 
 enum {
 	NVME_CC_ENABLE		= 1 << 0,
-	NVME_CC_CSS_NVM		= 0 << 4,
 	NVME_CC_EN_SHIFT	= 0,
 	NVME_CC_CSS_SHIFT	= 4,
 	NVME_CC_MPS_SHIFT	= 7,
@@ -219,6 +828,9 @@ enum {
 	NVME_CC_SHN_SHIFT	= 14,
 	NVME_CC_IOSQES_SHIFT	= 16,
 	NVME_CC_IOCQES_SHIFT	= 20,
+	NVME_CC_CSS_NVM		= 0 << NVME_CC_CSS_SHIFT,
+	NVME_CC_CSS_CSI		= 6 << NVME_CC_CSS_SHIFT,
+	NVME_CC_CSS_MASK	= 7 << NVME_CC_CSS_SHIFT,
 	NVME_CC_AMS_RR		= 0 << NVME_CC_AMS_SHIFT,
 	NVME_CC_AMS_WRRU	= 1 << NVME_CC_AMS_SHIFT,
 	NVME_CC_AMS_VS		= 7 << NVME_CC_AMS_SHIFT,
@@ -228,6 +840,8 @@ enum {
 	NVME_CC_SHN_MASK	= 3 << NVME_CC_SHN_SHIFT,
 	NVME_CC_IOSQES		= NVME_NVM_IOSQES << NVME_CC_IOSQES_SHIFT,
 	NVME_CC_IOCQES		= NVME_NVM_IOCQES << NVME_CC_IOCQES_SHIFT,
+	NVME_CAP_CSS_NVM	= 1 << 0,
+	NVME_CAP_CSS_CSI	= 1 << 6,
 	NVME_CSTS_RDY		= 1 << 0,
 	NVME_CSTS_CFS		= 1 << 1,
 	NVME_CSTS_NSSRO		= 1 << 4,
@@ -256,14 +870,16 @@ struct nvme_id_power_state {
 	__u8			rsvd23[9];
 };
 
-/* idle and active power scales occupy the last 2 bits of the field */
-#define POWER_SCALE(s) ((s) >> 6)
-
 enum {
 	NVME_PS_FLAGS_MAX_POWER_SCALE	= 1 << 0,
 	NVME_PS_FLAGS_NON_OP_STATE	= 1 << 1,
 };
 
+enum nvme_ctrl_attr {
+	NVME_CTRL_ATTR_HID_128_BIT	= (1 << 0),
+	NVME_CTRL_ATTR_TBKAS		= (1 << 6),
+};
+
 struct nvme_id_ctrl {
 	__le16			vid;
 	__le16			ssvid;
@@ -333,7 +949,7 @@ struct nvme_id_ctrl {
 	__u8			vwc;
 	__le16			awun;
 	__le16			awupf;
-	__u8			icsvscc;
+	__u8			nvscc;
 	__u8			nwpc;
 	__le16			acwu;
 	__le16			ocfs;
@@ -353,10 +969,13 @@ struct nvme_id_ctrl {
 };
 
 enum {
+	NVME_CTRL_CMIC_MULTI_CTRL		= 1 << 1,
+	NVME_CTRL_CMIC_ANA			= 1 << 3,
 	NVME_CTRL_ONCS_COMPARE			= 1 << 0,
 	NVME_CTRL_ONCS_WRITE_UNCORRECTABLE	= 1 << 1,
 	NVME_CTRL_ONCS_DSM			= 1 << 2,
 	NVME_CTRL_ONCS_WRITE_ZEROES		= 1 << 3,
+	NVME_CTRL_ONCS_RESERVATIONS		= 1 << 5,
 	NVME_CTRL_ONCS_TIMESTAMP		= 1 << 6,
 	NVME_CTRL_VWC_PRESENT			= 1 << 0,
 	NVME_CTRL_OACS_SEC_SUPP                 = 1 << 0,
@@ -422,8 +1041,28 @@ struct nvme_id_ns {
 	__u8			vs[3712];
 };
 
-struct nvme_id_iocs {
-	__le64 iocs[512];
+struct nvme_zns_lbafe {
+	__le64			zsze;
+	__u8			zdes;
+	__u8			rsvd9[7];
+};
+
+struct nvme_id_ns_zns {
+	__le16			zoc;
+	__le16			ozcs;
+	__le32			mar;
+	__le32			mor;
+	__le32			rrl;
+	__le32			frl;
+	__u8			rsvd20[2796];
+	struct nvme_zns_lbafe	lbafe[16];
+	__u8			rsvd3072[768];
+	__u8			vs[256];
+};
+
+struct nvme_id_ctrl_zns {
+	__u8	zasl;
+	__u8	rsvd1[4095];
 };
 
 enum {
@@ -432,9 +1071,9 @@ enum {
 	NVME_ID_CNS_NS_ACTIVE_LIST	= 0x02,
 	NVME_ID_CNS_NS_DESC_LIST	= 0x03,
 	NVME_ID_CNS_NVMSET_LIST		= 0x04,
-	NVME_ID_CNS_CSI_ID_NS		= 0x05,
-	NVME_ID_CNS_CSI_ID_CTRL		= 0x06,
-	NVME_ID_CNS_CSI_NS_ACTIVE_LIST = 0x07,
+	NVME_ID_CNS_CS_NS		= 0x05,
+	NVME_ID_CNS_CS_CTRL		= 0x06,
+	NVME_ID_CNS_CS_NS_ACTIVE_LIST	= 0x07,
 	NVME_ID_CNS_NS_PRESENT_LIST	= 0x10,
 	NVME_ID_CNS_NS_PRESENT		= 0x11,
 	NVME_ID_CNS_CTRL_NS_LIST	= 0x12,
@@ -442,9 +1081,15 @@ enum {
 	NVME_ID_CNS_SCNDRY_CTRL_LIST	= 0x15,
 	NVME_ID_CNS_NS_GRANULARITY	= 0x16,
 	NVME_ID_CNS_UUID_LIST		= 0x17,
-	NVME_ID_CNS_CSI_NS_PRESENT_LIST = 0x1a,
-	NVME_ID_CNS_CSI_NS_PRESENT  = 0x1b,
-	NVME_ID_CNS_CSI             = 0x1c,
+	NVME_ID_CNS_CSI_NS_PRESENT_LIST	= 0x1a,
+	NVME_ID_CNS_CSI_NS_PRESENT	= 0x1b,
+	NVME_ID_CNS_CSI			= 0x1c,
+
+};
+
+enum {
+	NVME_CSI_NVM			= 0,
+	NVME_CSI_ZNS			= 2,
 };
 
 enum {
@@ -461,130 +1106,51 @@ enum {
 };
 
 enum {
-	NVME_NS_FEAT_THIN	= 1 << 0,
-	NVME_NS_FLBAS_LBA_MASK	= 0xf,
-	NVME_NS_FLBAS_META_EXT	= 0x10,
-	NVME_LBAF_RP_BEST	= 0,
-	NVME_LBAF_RP_BETTER	= 1,
-	NVME_LBAF_RP_GOOD	= 2,
-	NVME_LBAF_RP_DEGRADED	= 3,
-	NVME_NS_DPC_PI_LAST	= 1 << 4,
-	NVME_NS_DPC_PI_FIRST	= 1 << 3,
-	NVME_NS_DPC_PI_TYPE3	= 1 << 2,
-	NVME_NS_DPC_PI_TYPE2	= 1 << 1,
-	NVME_NS_DPC_PI_TYPE1	= 1 << 0,
-	NVME_NS_DPS_PI_FIRST	= 1 << 3,
-	NVME_NS_DPS_PI_MASK	= 0x7,
-	NVME_NS_DPS_PI_TYPE1	= 1,
-	NVME_NS_DPS_PI_TYPE2	= 2,
-	NVME_NS_DPS_PI_TYPE3	= 3,
-};
-
-struct nvme_ns_id_desc {
-	__u8 nidt;
-	__u8 nidl;
-	__le16 reserved;
-};
-
-#define NVME_NIDT_EUI64_LEN	8
-#define NVME_NIDT_NGUID_LEN	16
-#define NVME_NIDT_UUID_LEN	16
-#define NVME_NIDT_CSI_LEN	1
-
-enum {
-	NVME_NIDT_EUI64		= 0x01,
-	NVME_NIDT_NGUID		= 0x02,
-	NVME_NIDT_UUID		= 0x03,
-	NVME_NIDT_CSI		= 0x04,
-};
-
-#define NVME_MAX_NVMSET		31
-
-struct nvme_nvmset_attr_entry {
-	__le16			id;
-	__le16			endurance_group_id;
-	__u8			rsvd4[4];
-	__le32			random_4k_read_typical;
-	__le32			opt_write_size;
-	__u8			total_nvmset_cap[16];
-	__u8			unalloc_nvmset_cap[16];
-	__u8			rsvd48[80];
-};
-
-struct nvme_id_nvmset {
-	__u8				nid;
-	__u8				rsvd1[127];
-	struct nvme_nvmset_attr_entry	ent[NVME_MAX_NVMSET];
-};
-
-struct nvme_id_ns_granularity_list_entry {
-	__le64			namespace_size_granularity;
-	__le64			namespace_capacity_granularity;
-};
-
-struct nvme_id_ns_granularity_list {
-	__le32			attributes;
-	__u8			num_descriptors;
-	__u8			rsvd[27];
-	struct nvme_id_ns_granularity_list_entry entry[16];
+	NVME_NS_FEAT_THIN	= 1 << 0,
+	NVME_NS_FEAT_ATOMICS	= 1 << 1,
+	NVME_NS_FEAT_IO_OPT	= 1 << 4,
+	NVME_NS_ATTR_RO		= 1 << 0,
+	NVME_NS_FLBAS_LBA_MASK	= 0xf,
+	NVME_NS_FLBAS_META_EXT	= 0x10,
+	NVME_NS_NMIC_SHARED	= 1 << 0,
+	NVME_LBAF_RP_BEST	= 0,
+	NVME_LBAF_RP_BETTER	= 1,
+	NVME_LBAF_RP_GOOD	= 2,
+	NVME_LBAF_RP_DEGRADED	= 3,
+	NVME_NS_DPC_PI_LAST	= 1 << 4,
+	NVME_NS_DPC_PI_FIRST	= 1 << 3,
+	NVME_NS_DPC_PI_TYPE3	= 1 << 2,
+	NVME_NS_DPC_PI_TYPE2	= 1 << 1,
+	NVME_NS_DPC_PI_TYPE1	= 1 << 0,
+	NVME_NS_DPS_PI_FIRST	= 1 << 3,
+	NVME_NS_DPS_PI_MASK	= 0x7,
+	NVME_NS_DPS_PI_TYPE1	= 1,
+	NVME_NS_DPS_PI_TYPE2	= 2,
+	NVME_NS_DPS_PI_TYPE3	= 3,
 };
 
-#define NVME_MAX_UUID_ENTRIES	128
-struct nvme_id_uuid_list_entry {
-	__u8			header;
-	__u8			rsvd1[15];
-	__u8			uuid[16];
+/* Identify Namespace Metadata Capabilities (MC): */
+enum {
+	NVME_MC_EXTENDED_LBA	= (1 << 0),
+	NVME_MC_METADATA_PTR	= (1 << 1),
 };
 
-struct nvme_id_uuid_list {
-	struct nvme_id_uuid_list_entry	entry[NVME_MAX_UUID_ENTRIES];
+struct nvme_ns_id_desc {
+	__u8 nidt;
+	__u8 nidl;
+	__le16 reserved;
 };
 
-/**
- * struct nvme_telemetry_log_page_hdr - structure for telemetry log page
- * @lpi: Log page identifier
- * @iee_oui: IEEE OUI Identifier
- * @dalb1: Data area 1 last block
- * @dalb2: Data area 2 last block
- * @dalb3: Data area 3 last block
- * @ctrlavail: Controller initiated data available
- * @ctrldgn: Controller initiated telemetry Data Generation Number
- * @rsnident: Reason Identifier
- * @telemetry_dataarea: Contains telemetry data block
- *
- * This structure can be used for both telemetry host-initiated log page
- * and controller-initiated log page.
- */
-struct nvme_telemetry_log_page_hdr {
-	__u8	lpi;
-	__u8	rsvd[4];
-	__u8	iee_oui[3];
-	__le16	dalb1;
-	__le16	dalb2;
-	__le16	dalb3;
-	__u8	rsvd1[368];
-	__u8	ctrlavail;
-	__u8	ctrldgn;
-	__u8	rsnident[128];
-	__u8	telemetry_dataarea[0];
-};
+#define NVME_NIDT_EUI64_LEN	8
+#define NVME_NIDT_NGUID_LEN	16
+#define NVME_NIDT_UUID_LEN	16
+#define NVME_NIDT_CSI_LEN	1
 
-struct nvme_endurance_group_log {
-	__u8	critical_warning;
-	__u8	rsvd1[2];
-	__u8	avl_spare;
-	__u8	avl_spare_threshold;
-	__u8	percent_used;
-	__u8	rsvd6[26];
-	__u8	endurance_estimate[16];
-	__u8	data_units_read[16];
-	__u8	data_units_written[16];
-	__u8	media_units_written[16];
-	__u8	host_read_cmds[16];
-	__u8	host_write_cmds[16];
-	__u8	media_data_integrity_err[16];
-	__u8	num_err_info_log_entries[16];
-	__u8	rsvd160[352];
+enum {
+	NVME_NIDT_EUI64		= 0x01,
+	NVME_NIDT_NGUID		= 0x02,
+	NVME_NIDT_UUID		= 0x03,
+	NVME_NIDT_CSI		= 0x04,
 };
 
 struct nvme_smart_log {
@@ -615,50 +1181,6 @@ struct nvme_smart_log {
 	__u8			rsvd232[280];
 };
 
-struct nvme_self_test_res {
-	__u8 			dsts;
-	__u8			seg;
-	__u8			vdi;
-	__u8			rsvd3;
-	__le64			poh;
-	__le32			nsid;
-	__le64			flba;
-	__u8			sct;
-	__u8			sc;
-	__u8			vs[2];
-} __attribute__((packed));
-
-enum {
-	NVME_ST_CODE_SHIFT    		= 4,
-	NVME_ST_CODE_SHORT_OP 		= 0x1,
-	NVME_ST_CODE_EXT_OP   		= 0x2,
-	NVME_ST_CODE_VS	      		= 0xe,
-	NVME_ST_RES_MASK      		= 0xf,
-	NVME_ST_RES_NO_ERR    		= 0x0,
-	NVME_ST_RES_ABORTED   		= 0x1,
-	NVME_ST_RES_CLR	      		= 0x2,
-	NVME_ST_RES_NS_REMOVED		= 0x3,
-	NVME_ST_RES_ABORTED_FORMAT	= 0x4,
-	NVME_ST_RES_FATAL_ERR		= 0x5,
-	NVME_ST_RES_UNKNOWN_SEG_FAIL	= 0x6,
-	NVME_ST_RES_KNOWN_SEG_FAIL	= 0x7,
-	NVME_ST_RES_ABORTED_UNKNOWN	= 0x8,
-	NVME_ST_RES_ABORTED_SANITIZE	= 0x9,
-	NVME_ST_RES_NOT_USED		= 0xf,
-	NVME_ST_VALID_NSID		= 1 << 0,
-	NVME_ST_VALID_FLBA		= 1 << 1,
-	NVME_ST_VALID_SCT		= 1 << 2,
-	NVME_ST_VALID_SC		= 1 << 3,
-	NVME_ST_REPORTS			= 20,
-};
-
-struct nvme_self_test_log {
-	__u8                      crnt_dev_selftest_oprn;
-	__u8                      crnt_dev_selftest_compln;
-	__u8                      rsvd[2];
-	struct nvme_self_test_res result[20];
-} __attribute__((packed));
-
 struct nvme_fw_slot_info_log {
 	__u8			afi;
 	__u8			rsvd1[7];
@@ -666,240 +1188,67 @@ struct nvme_fw_slot_info_log {
 	__u8			rsvd64[448];
 };
 
-struct nvme_lba_status_desc {
-	__u64 dslba;
-	__u32 nlb;
-	__u8 rsvd_12;
-	__u8 status;
-	__u8 rsvd_15_14[2];
-};
-
-struct nvme_lba_status {
-	__u32 nlsd;
-	__u8 cmpc;
-	__u8 rsvd_7_5[3];
-	struct nvme_lba_status_desc descs[0];
-};
-
-/* NVMe Namespace Write Protect State */
-enum {
-	NVME_NS_NO_WRITE_PROTECT = 0,
-	NVME_NS_WRITE_PROTECT,
-	NVME_NS_WRITE_PROTECT_POWER_CYCLE,
-	NVME_NS_WRITE_PROTECT_PERMANENT,
-};
-
-#define NVME_MAX_CHANGED_NAMESPACES     1024
-
-struct nvme_changed_ns_list_log {
-	__le32			log[NVME_MAX_CHANGED_NAMESPACES];
-};
-
 enum {
 	NVME_CMD_EFFECTS_CSUPP		= 1 << 0,
 	NVME_CMD_EFFECTS_LBCC		= 1 << 1,
 	NVME_CMD_EFFECTS_NCC		= 1 << 2,
-	NVME_CMD_EFFECTS_NIC		= 1 << 3,
-	NVME_CMD_EFFECTS_CCC		= 1 << 4,
-	NVME_CMD_EFFECTS_CSE_MASK	= 3 << 16,
-	NVME_CMD_EFFECTS_UUID_SEL	= 1 << 19,
-};
-
-struct nvme_effects_log {
-	__le32 acs[256];
-	__le32 iocs[256];
-	__u8   resv[2048];
-};
-
-enum nvme_ana_state {
-	NVME_ANA_OPTIMIZED		= 0x01,
-	NVME_ANA_NONOPTIMIZED		= 0x02,
-	NVME_ANA_INACCESSIBLE		= 0x03,
-	NVME_ANA_PERSISTENT_LOSS	= 0x04,
-	NVME_ANA_CHANGE			= 0x0f,
-};
-
-struct nvme_ana_group_desc {
-	__le32  grpid;
-	__le32  nnsids;
-	__le64  chgcnt;
-	__u8    state;
-	__u8    rsvd17[15];
-	__le32  nsids[];
-};
-
-/* flag for the log specific field of the ANA log */
-#define NVME_ANA_LOG_RGO   (1 << 0)
-
-struct nvme_ana_rsp_hdr {
-	__le64  chgcnt;
-	__le16  ngrps;
-	__le16  rsvd10[3];
-};
-
-/* persistent event type 02h */
-struct nvme_fw_commit_event {
-    __le64	old_fw_rev;
-    __le64 	new_fw_rev;
-    __u8 	fw_commit_action;
-    __u8 	fw_slot;
-    __u8 	sct_fw;
-    __u8 	sc_fw;
-    __le16 	vndr_assign_fw_commit_rc;
-} __attribute__((packed));
-
-/* persistent event type 03h */
-struct nvme_time_stamp_change_event {
-    __le64 	previous_timestamp;
-    __le64 	ml_secs_since_reset;
-};
-
-/* persistent event type 04h */
-struct nvme_power_on_reset_info_list {
-    __le16   cid;
-    __u8     fw_act;
-    __u8     op_in_prog;
-    __u8     rsvd4[12];
-    __le32   ctrl_power_cycle;
-    __le64   power_on_ml_seconds;
-    __le64   ctrl_time_stamp;
-} __attribute__((packed));
-
-/* persistent event type 05h */
-struct nvme_nss_hw_err_event {
-    __le16 	nss_hw_err_event_code;
-    __u8 	rsvd2[2];
-    __u8 	*add_hw_err_info;
-};
-
-/* persistent event type 06h */
-struct nvme_change_ns_event {
-	__le32	nsmgt_cdw10;
-	__u8	rsvd4[4];
-	__le64	nsze;
-	__u8	nscap[16];
-	__u8	flbas;
-	__u8	dps;
-	__u8	nmic;
-	__u8	rsvd35;
-	__le32	ana_grp_id;
-	__le16	nvmset_id;
-	__le16	rsvd42;
-	__le32	nsid;
-};
-
-/* persistent event type 07h */
-struct nvme_format_nvm_start_event {
-    __le32 	nsid;
-    __u8 	fna;
-    __u8 	rsvd5[3];
-    __le32 	format_nvm_cdw10;
-};
-
-/* persistent event type 08h */
-struct nvme_format_nvm_compln_event {
-    __le32 	nsid;
-    __u8 	smallest_fpi;
-    __u8 	format_nvm_status;
-    __le16 	compln_info;
-    __le32 	status_field;
-};
-
-/* persistent event type 09h */
-struct nvme_sanitize_start_event {
-    __le32 	sani_cap;
-    __le32 	sani_cdw10;
-    __le32 	sani_cdw11;
+	NVME_CMD_EFFECTS_NIC		= 1 << 3,
+	NVME_CMD_EFFECTS_CCC		= 1 << 4,
+	NVME_CMD_EFFECTS_CSE_MASK	= 3 << 16,
+	NVME_CMD_EFFECTS_UUID_SEL	= 1 << 19,
 };
 
-/* persistent event type 0Ah */
-struct nvme_sanitize_compln_event {
-    __le16 	sani_prog;
-    __le16 	sani_status;
-    __le16 	cmpln_info;
-	__u8 	rsvd6[2];
+struct nvme_effects_log {
+	__le32 acs[256];
+	__le32 iocs[256];
+	__u8   resv[2048];
 };
 
-/* persistent event type 0Dh */
-struct nvme_thermal_exc_event {
-    __u8 	over_temp;
-    __u8 	threshold;
+enum nvme_ana_state {
+	NVME_ANA_OPTIMIZED		= 0x01,
+	NVME_ANA_NONOPTIMIZED		= 0x02,
+	NVME_ANA_INACCESSIBLE		= 0x03,
+	NVME_ANA_PERSISTENT_LOSS	= 0x04,
+	NVME_ANA_CHANGE			= 0x0f,
 };
 
-/* persistent event entry head */
-struct nvme_persistent_event_entry_head {
-	__u8	etype;
-	__u8	etype_rev;
-	__u8	ehl;
-	__u8	rsvd3;
-	__le16	ctrl_id;
-	__le64	etimestamp;
-	__u8	rsvd14[6];
-	__le16	vsil;
-	__le16	el;
-} __attribute__((packed));
+struct nvme_ana_group_desc {
+	__le32	grpid;
+	__le32	nnsids;
+	__le64	chgcnt;
+	__u8	state;
+	__u8	rsvd17[15];
+	__le32	nsids[];
+};
 
-/* persistent event log head */
-struct nvme_persistent_event_log_head {
-	__u8	log_id;
-	__u8	rsvd1[3];
-	__le32	tnev;
-	__le64	tll;
-	__u8	log_rev;
-	__u8	rsvd17;
-	__le16	head_len;
-	__le64	timestamp;
-	__u8	poh[16];
-	__le64	pcc;
-	__le16	vid;
-	__le16	ssvid;
-	__u8	sn[20];
-	__u8	mn[40];
-	__u8	subnqn[256];
-	__u8    rsvd372[108];
-	__u8	supp_event_bm[32];
-} __attribute__((packed));
+/* flag for the log specific field of the ANA log */
+#define NVME_ANA_LOG_RGO	(1 << 0)
 
-enum nvme_persistent_event_types {
-    NVME_SMART_HEALTH_EVENT         = 0x01,
-    NVME_FW_COMMIT_EVENT            = 0x02,
-    NVME_TIMESTAMP_EVENT            = 0x03,
-    NVME_POWER_ON_RESET_EVENT       = 0x04,
-    NVME_NSS_HW_ERROR_EVENT         = 0x05,
-    NVME_CHANGE_NS_EVENT            = 0x06,
-    NVME_FORMAT_START_EVENT         = 0x07,
-    NVME_FORMAT_COMPLETION_EVENT    = 0x08,
-    NVME_SANITIZE_START_EVENT       = 0x09,
-    NVME_SANITIZE_COMPLETION_EVENT  = 0x0a,
-    NVME_THERMAL_EXCURSION_EVENT    = 0x0d
+struct nvme_ana_rsp_hdr {
+	__le64	chgcnt;
+	__le16	ngrps;
+	__le16	rsvd10[3];
 };
 
-enum nvme_persistent_event_log_actions {
-	NVME_PEVENT_LOG_READ				= 0x0,
-	NVME_PEVENT_LOG_EST_CTX_AND_READ	= 0x1,
-	NVME_PEVENT_LOG_RELEASE_CTX			= 0x2,
+struct nvme_zone_descriptor {
+	__u8		zt;
+	__u8		zs;
+	__u8		za;
+	__u8		rsvd3[5];
+	__le64		zcap;
+	__le64		zslba;
+	__le64		wp;
+	__u8		rsvd32[32];
 };
 
-struct nvme_predlat_event_agg_log_page {
-	__le64	num_entries;
-	__le16	entries[];
+enum {
+	NVME_ZONE_TYPE_SEQWRITE_REQ	= 0x2,
 };
 
-struct nvme_predlat_per_nvmset_log_page {
-	__u8	status;
-	__u8	rsvd1;
-	__le16	event_type;
-	__u8	rsvd4[28];
-	__le64	dtwin_rtyp;
-	__le64	dtwin_wtyp;
-	__le64	dtwin_timemax;
-	__le64	ndwin_timemin_high;
-	__le64	ndwin_timemin_low;
-	__u8	rsvd72[56];
-	__le64	dtwin_restimate;
-	__le64	dtwin_westimate;
-	__le64	dtwin_testimate;
-	__u8	rsvd152[360];
+struct nvme_zone_report {
+	__le64		nr_zones;
+	__u8		resv8[56];
+	struct nvme_zone_descriptor entries[];
 };
 
 enum {
@@ -913,10 +1262,32 @@ enum {
 enum {
 	NVME_AER_ERROR			= 0,
 	NVME_AER_SMART			= 1,
+	NVME_AER_NOTICE			= 2,
 	NVME_AER_CSS			= 6,
 	NVME_AER_VS			= 7,
 };
 
+enum {
+	NVME_AER_NOTICE_NS_CHANGED	= 0x00,
+	NVME_AER_NOTICE_FW_ACT_STARTING = 0x01,
+	NVME_AER_NOTICE_ANA		= 0x03,
+	NVME_AER_NOTICE_DISC_CHANGED	= 0xf0,
+};
+
+enum {
+	NVME_AEN_BIT_NS_ATTR		= 8,
+	NVME_AEN_BIT_FW_ACT		= 9,
+	NVME_AEN_BIT_ANA_CHANGE		= 11,
+	NVME_AEN_BIT_DISC_CHANGE	= 31,
+};
+
+enum {
+	NVME_AEN_CFG_NS_ATTR		= 1 << NVME_AEN_BIT_NS_ATTR,
+	NVME_AEN_CFG_FW_ACT		= 1 << NVME_AEN_BIT_FW_ACT,
+	NVME_AEN_CFG_ANA_CHANGE		= 1 << NVME_AEN_BIT_ANA_CHANGE,
+	NVME_AEN_CFG_DISC_CHANGE	= 1 << NVME_AEN_BIT_DISC_CHANGE,
+};
+
 struct nvme_lba_range_type {
 	__u8			type;
 	__u8			attributes;
@@ -937,16 +1308,6 @@ enum {
 	NVME_LBART_ATTRIB_HIDE	= 1 << 1,
 };
 
-/* Predictable Latency Mode - Deterministic Threshold Configuration Data */
-struct nvme_plm_config {
-	__le16	enable_event;
-	__u8	rsvd2[30];
-	__le64	dtwin_reads_thresh;
-	__le64	dtwin_writes_thresh;
-	__le64	dtwin_time_thresh;
-	__u8	rsvd56[456];
-};
-
 struct nvme_reservation_status {
 	__le32	gen;
 	__u8	rtype;
@@ -963,24 +1324,6 @@ struct nvme_reservation_status {
 	} regctl_ds[];
 };
 
-struct nvme_reservation_status_ext {
-	__le32	gen;
-	__u8	rtype;
-	__u8	regctl[2];
-	__u8	resv5[2];
-	__u8	ptpls;
-	__u8	resv10[14];
-	__u8	resv24[40];
-	struct {
-		__le16	cntlid;
-		__u8	rcsts;
-		__u8	resv3[5];
-		__le64	rkey;
-		__u8	hostid[16];
-		__u8	resv32[32];
-	} regctl_eds[];
-};
-
 enum nvme_async_event_type {
 	NVME_AER_TYPE_ERROR	= 0,
 	NVME_AER_TYPE_SMART	= 1,
@@ -1003,10 +1346,26 @@ enum nvme_opcode {
 	nvme_cmd_resv_acquire	= 0x11,
 	nvme_cmd_resv_release	= 0x15,
 	nvme_cmd_copy		= 0x19,
-	nvme_zns_cmd_mgmt_send	= 0x79,
-	nvme_zns_cmd_mgmt_recv	= 0x7a,
-	nvme_zns_cmd_append	= 0x7d,
-};
+	nvme_cmd_zone_mgmt_send	= 0x79,
+	nvme_cmd_zone_mgmt_recv	= 0x7a,
+	nvme_cmd_zone_append	= 0x7d,
+};
+
+#define nvme_opcode_name(opcode)	{ opcode, #opcode }
+#define show_nvm_opcode_name(val)				\
+	__print_symbolic(val,					\
+		nvme_opcode_name(nvme_cmd_flush),		\
+		nvme_opcode_name(nvme_cmd_write),		\
+		nvme_opcode_name(nvme_cmd_read),		\
+		nvme_opcode_name(nvme_cmd_write_uncor),		\
+		nvme_opcode_name(nvme_cmd_compare),		\
+		nvme_opcode_name(nvme_cmd_write_zeroes),	\
+		nvme_opcode_name(nvme_cmd_dsm),			\
+		nvme_opcode_name(nvme_cmd_resv_register),	\
+		nvme_opcode_name(nvme_cmd_resv_report),		\
+		nvme_opcode_name(nvme_cmd_resv_acquire),	\
+		nvme_opcode_name(nvme_cmd_resv_release))
+
 
 /*
  * Descriptor subtype - lower 4 bits of nvme_(keyed_)sgl_desc identifier
@@ -1092,10 +1451,43 @@ enum {
 	NVME_CMD_SGL_ALL	= NVME_CMD_SGL_METABUF | NVME_CMD_SGL_METASEG,
 };
 
+struct nvme_common_command {
+	__u8			opcode;
+	__u8			flags;
+	__u16			command_id;
+	__le32			nsid;
+	__le32			cdw2[2];
+	__le64			metadata;
+	union nvme_data_ptr	dptr;
+	__le32			cdw10;
+	__le32			cdw11;
+	__le32			cdw12;
+	__le32			cdw13;
+	__le32			cdw14;
+	__le32			cdw15;
+};
+
+struct nvme_rw_command {
+	__u8			opcode;
+	__u8			flags;
+	__u16			command_id;
+	__le32			nsid;
+	__u64			rsvd2;
+	__le64			metadata;
+	union nvme_data_ptr	dptr;
+	__le64			slba;
+	__le16			length;
+	__le16			control;
+	__le32			dsmgmt;
+	__le32			reftag;
+	__le16			apptag;
+	__le16			appmask;
+};
+
 enum {
 	NVME_RW_LR			= 1 << 15,
 	NVME_RW_FUA			= 1 << 14,
-	NVME_RW_DEAC			= 1 << 9,
+	NVME_RW_APPEND_PIREMAP		= 1 << 9,
 	NVME_RW_DSM_FREQ_UNSPEC		= 0,
 	NVME_RW_DSM_FREQ_TYPICAL	= 1,
 	NVME_RW_DSM_FREQ_RARE		= 2,
@@ -1118,6 +1510,18 @@ enum {
 	NVME_RW_DTYPE_STREAMS		= 1 << 4,
 };
 
+struct nvme_dsm_cmd {
+	__u8			opcode;
+	__u8			flags;
+	__u16			command_id;
+	__le32			nsid;
+	__u64			rsvd2[2];
+	union nvme_data_ptr	dptr;
+	__le32			nr;
+	__le32			attributes;
+	__u32			rsvd12[4];
+};
+
 enum {
 	NVME_DSMGMT_IDR		= 1 << 0,
 	NVME_DSMGMT_IDW		= 1 << 1,
@@ -1132,17 +1536,78 @@ struct nvme_dsm_range {
 	__le64			slba;
 };
 
-struct nvme_copy_range {
-	__u8			rsvd0[8];
+struct nvme_write_zeroes_cmd {
+	__u8			opcode;
+	__u8			flags;
+	__u16			command_id;
+	__le32			nsid;
+	__u64			rsvd2;
+	__le64			metadata;
+	union nvme_data_ptr	dptr;
 	__le64			slba;
-	__le16			nlb;
-	__u8			rsvd18[6];
-	__le32			eilbrt;
-	__le16			elbatm;
-	__le16			elbat;
+	__le16			length;
+	__le16			control;
+	__le32			dsmgmt;
+	__le32			reftag;
+	__le16			apptag;
+	__le16			appmask;
+};
+
+enum nvme_zone_mgmt_action {
+	NVME_ZONE_CLOSE		= 0x1,
+	NVME_ZONE_FINISH	= 0x2,
+	NVME_ZONE_OPEN		= 0x3,
+	NVME_ZONE_RESET		= 0x4,
+	NVME_ZONE_OFFLINE	= 0x5,
+	NVME_ZONE_SET_DESC_EXT	= 0x10,
+};
+
+struct nvme_zone_mgmt_send_cmd {
+	__u8			opcode;
+	__u8			flags;
+	__u16			command_id;
+	__le32			nsid;
+	__le32			cdw2[2];
+	__le64			metadata;
+	union nvme_data_ptr	dptr;
+	__le64			slba;
+	__le32			cdw12;
+	__u8			zsa;
+	__u8			select_all;
+	__u8			rsvd13[2];
+	__le32			cdw14[2];
+};
+
+struct nvme_zone_mgmt_recv_cmd {
+	__u8			opcode;
+	__u8			flags;
+	__u16			command_id;
+	__le32			nsid;
+	__le64			rsvd2[2];
+	union nvme_data_ptr	dptr;
+	__le64			slba;
+	__le32			numd;
+	__u8			zra;
+	__u8			zrasf;
+	__u8			pr;
+	__u8			rsvd13;
+	__le32			cdw14[2];
+};
+
+enum {
+	NVME_ZRA_ZONE_REPORT		= 0,
+	NVME_ZRASF_ZONE_REPORT_ALL	= 0,
+	NVME_REPORT_ZONE_PARTIAL	= 1,
 };
 
 /* Features */
+
+enum {
+	NVME_TEMP_THRESH_MASK		= 0xffff,
+	NVME_TEMP_THRESH_SELECT_SHIFT	= 16,
+	NVME_TEMP_THRESH_TYPE_UNDER	= 0x100000,
+};
+
 struct nvme_feat_auto_pst {
 	__le64 entries[32];
 };
@@ -1152,6 +1617,15 @@ enum {
 	NVME_HOST_MEM_RETURN	= (1 << 1),
 };
 
+struct nvme_feat_host_behavior {
+	__u8 acre;
+	__u8 resv1[511];
+};
+
+enum {
+	NVME_ENABLE_ACRE	= 1,
+};
+
 /* Admin commands */
 
 enum nvme_admin_opcode {
@@ -1182,7 +1656,35 @@ enum nvme_admin_opcode {
 	nvme_admin_security_recv	= 0x82,
 	nvme_admin_sanitize_nvm		= 0x84,
 	nvme_admin_get_lba_status	= 0x86,
-};
+	nvme_admin_vendor_start		= 0xC0,
+};
+
+#define nvme_admin_opcode_name(opcode)	{ opcode, #opcode }
+#define show_admin_opcode_name(val)					\
+	__print_symbolic(val,						\
+		nvme_admin_opcode_name(nvme_admin_delete_sq),		\
+		nvme_admin_opcode_name(nvme_admin_create_sq),		\
+		nvme_admin_opcode_name(nvme_admin_get_log_page),	\
+		nvme_admin_opcode_name(nvme_admin_delete_cq),		\
+		nvme_admin_opcode_name(nvme_admin_create_cq),		\
+		nvme_admin_opcode_name(nvme_admin_identify),		\
+		nvme_admin_opcode_name(nvme_admin_abort_cmd),		\
+		nvme_admin_opcode_name(nvme_admin_set_features),	\
+		nvme_admin_opcode_name(nvme_admin_get_features),	\
+		nvme_admin_opcode_name(nvme_admin_async_event),		\
+		nvme_admin_opcode_name(nvme_admin_ns_mgmt),		\
+		nvme_admin_opcode_name(nvme_admin_activate_fw),		\
+		nvme_admin_opcode_name(nvme_admin_download_fw),		\
+		nvme_admin_opcode_name(nvme_admin_ns_attach),		\
+		nvme_admin_opcode_name(nvme_admin_keep_alive),		\
+		nvme_admin_opcode_name(nvme_admin_directive_send),	\
+		nvme_admin_opcode_name(nvme_admin_directive_recv),	\
+		nvme_admin_opcode_name(nvme_admin_dbbuf),		\
+		nvme_admin_opcode_name(nvme_admin_format_nvm),		\
+		nvme_admin_opcode_name(nvme_admin_security_send),	\
+		nvme_admin_opcode_name(nvme_admin_security_recv),	\
+		nvme_admin_opcode_name(nvme_admin_sanitize_nvm),	\
+		nvme_admin_opcode_name(nvme_admin_get_lba_status))
 
 enum {
 	NVME_QUEUE_PHYS_CONTIG	= (1 << 0),
@@ -1191,30 +1693,6 @@ enum {
 	NVME_SQ_PRIO_HIGH	= (1 << 1),
 	NVME_SQ_PRIO_MEDIUM	= (2 << 1),
 	NVME_SQ_PRIO_LOW	= (3 << 1),
-	NVME_LOG_ERROR		= 0x01,
-	NVME_LOG_SMART		= 0x02,
-	NVME_LOG_FW_SLOT	= 0x03,
-	NVME_LOG_CHANGED_NS	= 0x04,
-	NVME_LOG_CMD_EFFECTS	= 0x05,
-	NVME_LOG_DEVICE_SELF_TEST = 0x06,
-	NVME_LOG_TELEMETRY_HOST = 0x07,
-	NVME_LOG_TELEMETRY_CTRL = 0x08,
-	NVME_LOG_ENDURANCE_GROUP = 0x09,
-	NVME_LOG_PRELAT_PER_NVMSET	= 0x0a,
-	NVME_LOG_ANA		= 0x0c,
-	NVME_LOG_PRELAT_EVENT_AGG	= 0x0b,
-	NVME_LOG_PERSISTENT_EVENT   = 0x0d,
-	NVME_LOG_DISC		= 0x70,
-	NVME_LOG_RESERVATION	= 0x80,
-	NVME_LOG_SANITIZE	= 0x81,
-	NVME_LOG_ZONE_CHANGED_LIST = 0xbf,
-	NVME_FWACT_REPL		= (0 << 3),
-	NVME_FWACT_REPL_ACTV	= (1 << 3),
-	NVME_FWACT_ACTV		= (2 << 3),
-};
-
-enum nvme_feat {
-	NVME_FEAT_NONE = 0x0,
 	NVME_FEAT_ARBITRATION	= 0x01,
 	NVME_FEAT_POWER_MGMT	= 0x02,
 	NVME_FEAT_LBA_RANGE	= 0x03,
@@ -1230,8 +1708,8 @@ enum nvme_feat {
 	NVME_FEAT_HOST_MEM_BUF	= 0x0d,
 	NVME_FEAT_TIMESTAMP	= 0x0e,
 	NVME_FEAT_KATO		= 0x0f,
-	NVME_FEAT_HCTM		= 0X10,
-	NVME_FEAT_NOPSC		= 0X11,
+	NVME_FEAT_HCTM		= 0x10,
+	NVME_FEAT_NOPSC		= 0x11,
 	NVME_FEAT_RRL		= 0x12,
 	NVME_FEAT_PLM_CONFIG	= 0x13,
 	NVME_FEAT_PLM_WINDOW	= 0x14,
@@ -1243,58 +1721,187 @@ enum nvme_feat {
 	NVME_FEAT_RESV_MASK	= 0x82,
 	NVME_FEAT_RESV_PERSIST	= 0x83,
 	NVME_FEAT_WRITE_PROTECT	= 0x84,
-} __attribute__ ((__packed__));
+	NVME_FEAT_VENDOR_START	= 0xC0,
+	NVME_FEAT_VENDOR_END	= 0xFF,
+	NVME_LOG_ERROR		= 0x01,
+	NVME_LOG_SMART		= 0x02,
+	NVME_LOG_FW_SLOT	= 0x03,
+	NVME_LOG_CHANGED_NS	= 0x04,
+	NVME_LOG_CMD_EFFECTS	= 0x05,
+	NVME_LOG_DEVICE_SELF_TEST = 0x06,
+	NVME_LOG_TELEMETRY_HOST = 0x07,
+	NVME_LOG_TELEMETRY_CTRL = 0x08,
+	NVME_LOG_ENDURANCE_GROUP = 0x09,
+	NVME_LOG_PRELAT_PER_NVMSET	= 0x0a,
+	NVME_LOG_PRELAT_EVENT_AGG	= 0x0b,
+	NVME_LOG_ANA		= 0x0c,
+	NVME_LOG_PERSISTENT_EVENT   = 0x0d,
+	NVME_LOG_DISC		= 0x70,
+	NVME_LOG_RESERVATION	= 0x80,
+	NVME_LOG_SANITIZE	= 0x81,
+	NVME_LOG_ZONE_CHANGED_LIST = 0xbf,
+	NVME_FWACT_REPL		= (0 << 3),
+	NVME_FWACT_REPL_ACTV	= (1 << 3),
+	NVME_FWACT_ACTV		= (2 << 3),
+};
 
+/* NVMe Namespace Write Protect State */
 enum {
-	NVME_NO_LOG_LSP       = 0x0,
-	NVME_NO_LOG_LPO       = 0x0,
-	NVME_LOG_ANA_LSP_RGO  = 0x1,
-	NVME_TELEM_LSP_CREATE = 0x1,
+	NVME_NS_NO_WRITE_PROTECT = 0,
+	NVME_NS_WRITE_PROTECT,
+	NVME_NS_WRITE_PROTECT_POWER_CYCLE,
+	NVME_NS_WRITE_PROTECT_PERMANENT,
 };
 
-/* Sanitize and Sanitize Monitor/Log */
-enum {
-	/* Sanitize */
-	NVME_SANITIZE_NO_DEALLOC	= 0x00000200,
-	NVME_SANITIZE_OIPBP		= 0x00000100,
-	NVME_SANITIZE_OWPASS_SHIFT	= 0x00000004,
-	NVME_SANITIZE_AUSE		= 0x00000008,
-	NVME_SANITIZE_ACT_CRYPTO_ERASE	= 0x00000004,
-	NVME_SANITIZE_ACT_OVERWRITE	= 0x00000003,
-	NVME_SANITIZE_ACT_BLOCK_ERASE	= 0x00000002,
-	NVME_SANITIZE_ACT_EXIT		= 0x00000001,
+#define NVME_MAX_CHANGED_NAMESPACES	1024
 
-	/* Sanitize Monitor/Log */
-	NVME_SANITIZE_LOG_DATA_LEN		= 0x0014,
-	NVME_SANITIZE_LOG_GLOBAL_DATA_ERASED	= 0x0100,
-	NVME_SANITIZE_LOG_NUM_CMPLTED_PASS_MASK	= 0x00F8,
-	NVME_SANITIZE_LOG_STATUS_MASK		= 0x0007,
-	NVME_SANITIZE_LOG_NEVER_SANITIZED	= 0x0000,
-	NVME_SANITIZE_LOG_COMPLETED_SUCCESS	= 0x0001,
-	NVME_SANITIZE_LOG_IN_PROGESS		= 0x0002,
-	NVME_SANITIZE_LOG_COMPLETED_FAILED	= 0x0003,
-	NVME_SANITIZE_LOG_ND_COMPLETED_SUCCESS	= 0x0004,
+struct nvme_identify {
+	__u8			opcode;
+	__u8			flags;
+	__u16			command_id;
+	__le32			nsid;
+	__u64			rsvd2[2];
+	union nvme_data_ptr	dptr;
+	__u8			cns;
+	__u8			rsvd3;
+	__le16			ctrlid;
+	__u8			rsvd11[3];
+	__u8			csi;
+	__u32			rsvd12[4];
 };
 
 #define NVME_IDENTIFY_DATA_SIZE 4096
 
+struct nvme_features {
+	__u8			opcode;
+	__u8			flags;
+	__u16			command_id;
+	__le32			nsid;
+	__u64			rsvd2[2];
+	union nvme_data_ptr	dptr;
+	__le32			fid;
+	__le32			dword11;
+	__le32                  dword12;
+	__le32                  dword13;
+	__le32                  dword14;
+	__le32                  dword15;
+};
+
 struct nvme_host_mem_buf_desc {
 	__le64			addr;
 	__le32			size;
 	__u32			rsvd;
 };
 
-/* Sanitize Log Page */
-struct nvme_sanitize_log_page {
-	__le16			progress;
-	__le16			status;
-	__le32			cdw10_info;
-	__le32			est_ovrwrt_time;
-	__le32			est_blk_erase_time;
-	__le32			est_crypto_erase_time;
-	__le32			est_ovrwrt_time_with_no_deallocate;
-	__le32			est_blk_erase_time_with_no_deallocate;
-	__le32			est_crypto_erase_time_with_no_deallocate;
+struct nvme_create_cq {
+	__u8			opcode;
+	__u8			flags;
+	__u16			command_id;
+	__u32			rsvd1[5];
+	__le64			prp1;
+	__u64			rsvd8;
+	__le16			cqid;
+	__le16			qsize;
+	__le16			cq_flags;
+	__le16			irq_vector;
+	__u32			rsvd12[4];
+};
+
+struct nvme_create_sq {
+	__u8			opcode;
+	__u8			flags;
+	__u16			command_id;
+	__u32			rsvd1[5];
+	__le64			prp1;
+	__u64			rsvd8;
+	__le16			sqid;
+	__le16			qsize;
+	__le16			sq_flags;
+	__le16			cqid;
+	__u32			rsvd12[4];
+};
+
+struct nvme_delete_queue {
+	__u8			opcode;
+	__u8			flags;
+	__u16			command_id;
+	__u32			rsvd1[9];
+	__le16			qid;
+	__u16			rsvd10;
+	__u32			rsvd11[5];
+};
+
+struct nvme_abort_cmd {
+	__u8			opcode;
+	__u8			flags;
+	__u16			command_id;
+	__u32			rsvd1[9];
+	__le16			sqid;
+	__u16			cid;
+	__u32			rsvd11[5];
+};
+
+struct nvme_download_firmware {
+	__u8			opcode;
+	__u8			flags;
+	__u16			command_id;
+	__u32			rsvd1[5];
+	union nvme_data_ptr	dptr;
+	__le32			numd;
+	__le32			offset;
+	__u32			rsvd12[4];
+};
+
+struct nvme_format_cmd {
+	__u8			opcode;
+	__u8			flags;
+	__u16			command_id;
+	__le32			nsid;
+	__u64			rsvd2[4];
+	__le32			cdw10;
+	__u32			rsvd11[5];
+};
+
+struct nvme_get_log_page_command {
+	__u8			opcode;
+	__u8			flags;
+	__u16			command_id;
+	__le32			nsid;
+	__u64			rsvd2[2];
+	union nvme_data_ptr	dptr;
+	__u8			lid;
+	__u8			lsp; /* upper 4 bits reserved */
+	__le16			numdl;
+	__le16			numdu;
+	__u16			rsvd11;
+	union {
+		struct {
+			__le32 lpol;
+			__le32 lpou;
+		};
+		__le64 lpo;
+	};
+	__u8			rsvd14[3];
+	__u8			csi;
+	__u32			rsvd15;
+};
+
+struct nvme_directive_cmd {
+	__u8			opcode;
+	__u8			flags;
+	__u16			command_id;
+	__le32			nsid;
+	__u64			rsvd2[2];
+	union nvme_data_ptr	dptr;
+	__le32			numd;
+	__u8			doper;
+	__u8			dtype;
+	__le16			dspec;
+	__u8			endir;
+	__u8			tdtype;
+	__u16			rsvd15;
+
+	__u32			rsvd16[3];
 };
 
 /*
@@ -1310,6 +1917,32 @@ enum nvmf_capsule_command {
 	nvme_fabrics_type_property_get	= 0x04,
 };
 
+#define nvme_fabrics_type_name(type)   { type, #type }
+#define show_fabrics_type_name(type)					\
+	__print_symbolic(type,						\
+		nvme_fabrics_type_name(nvme_fabrics_type_property_set),	\
+		nvme_fabrics_type_name(nvme_fabrics_type_connect),	\
+		nvme_fabrics_type_name(nvme_fabrics_type_property_get))
+
+/*
+ * If not fabrics command, fctype will be ignored.
+ */
+#define show_opcode_name(qid, opcode, fctype)			\
+	((opcode) == nvme_fabrics_command ?			\
+	 show_fabrics_type_name(fctype) :			\
+	((qid) ?						\
+	 show_nvm_opcode_name(opcode) :				\
+	 show_admin_opcode_name(opcode)))
+
+struct nvmf_common_command {
+	__u8	opcode;
+	__u8	resv1;
+	__u16	command_id;
+	__u8	fctype;
+	__u8	resv2[35];
+	__u8	ts[24];
+};
+
 /*
  * The legal cntlid range a NVMe Target will provide.
  * Note that cntlid of value 0 is considered illegal in the fabrics world.
@@ -1358,7 +1991,27 @@ struct nvmf_disc_rsp_page_hdr {
 	__le64		numrec;
 	__le16		recfmt;
 	__u8		resv14[1006];
-	struct nvmf_disc_rsp_page_entry entries[0];
+	struct nvmf_disc_rsp_page_entry entries[];
+};
+
+enum {
+	NVME_CONNECT_DISABLE_SQFLOW	= (1 << 2),
+};
+
+struct nvmf_connect_command {
+	__u8		opcode;
+	__u8		resv1;
+	__u16		command_id;
+	__u8		fctype;
+	__u8		resv2[19];
+	union nvme_data_ptr dptr;
+	__le16		recfmt;
+	__le16		qid;
+	__le16		sqsize;
+	__u8		cattr;
+	__u8		resv3;
+	__le32		kato;
+	__u8		resv4[12];
 };
 
 struct nvmf_connect_data {
@@ -1370,6 +2023,41 @@ struct nvmf_connect_data {
 	char		resv5[256];
 };
 
+struct nvmf_property_set_command {
+	__u8		opcode;
+	__u8		resv1;
+	__u16		command_id;
+	__u8		fctype;
+	__u8		resv2[35];
+	__u8		attrib;
+	__u8		resv3[3];
+	__le32		offset;
+	__le64		value;
+	__u8		resv4[8];
+};
+
+struct nvmf_property_get_command {
+	__u8		opcode;
+	__u8		resv1;
+	__u16		command_id;
+	__u8		fctype;
+	__u8		resv2[35];
+	__u8		attrib;
+	__u8		resv3[3];
+	__le32		offset;
+	__u8		resv4[16];
+};
+
+struct nvme_dbbuf {
+	__u8			opcode;
+	__u8			flags;
+	__u16			command_id;
+	__u32			rsvd1[5];
+	__le64			prp1;
+	__le64			prp2;
+	__u32			rsvd12[6];
+};
+
 struct streams_directive_params {
 	__le16	msl;
 	__le16	nssa;
@@ -1382,113 +2070,62 @@ struct streams_directive_params {
 	__u8	rsvd2[6];
 };
 
-struct nvme_effects_log_page {
-	__le32 acs[256];
-	__le32 iocs[256];
-	__u8   resv[2048];
-};
-
-struct nvme_error_log_page {
-	__le64	error_count;
-	__le16	sqid;
-	__le16	cmdid;
-	__le16	status_field;
-	__le16	parm_error_location;
-	__le64	lba;
-	__le32	nsid;
-	__u8	vs;
-	__u8	trtype;
-	__u8	resv[2];
-	__le64	cs;
-	__le16	trtype_spec_info;
-	__u8	resv2[22];
-};
-
-struct nvme_firmware_log_page {
-	__u8	afi;
-	__u8	resv[7];
-	__u64	frs[7];
-	__u8	resv2[448];
-};
-
-struct nvme_host_mem_buffer {
-	__u32			hsize;
-	__u32			hmdlal;
-	__u32			hmdlau;
-	__u32			hmdlec;
-	__u8			rsvd16[4080];
-};
-
-struct nvme_auto_pst {
-	__u32	data;
-	__u32	rsvd32;
-};
-
-struct nvme_timestamp {
-	__u8 timestamp[6];
-	__u8 attr;
-	__u8 rsvd;
-};
-
-struct nvme_controller_list {
-	__le16 num;
-	__le16 identifier[2047];
-};
-
-struct nvme_secondary_controller_entry {
-	__le16 scid;	/* Secondary Controller Identifier */
-	__le16 pcid;	/* Primary Controller Identifier */
-	__u8   scs;	/* Secondary Controller State */
-	__u8   rsvd5[3];
-	__le16 vfn;	/* Virtual Function Number */
-	__le16 nvq;	/* Number of VQ Flexible Resources Assigned */
-	__le16 nvi;	/* Number of VI Flexible Resources Assigned */
-	__u8   rsvd14[18];
-};
-
-struct nvme_secondary_controllers_list {
-	__u8   num;
-	__u8   rsvd[31];
-	struct nvme_secondary_controller_entry sc_entry[127];
-};
-
-struct nvme_bar_cap {
-	__u16	mqes;
-	__u8	ams_cqr;
-	__u8	to;
-	__u16	bps_css_nssrs_dstrd;
-	__u8	mpsmax_mpsmin;
-	__u8	rsvd_cmbs_pmrs;
+struct nvme_command {
+	union {
+		struct nvme_common_command common;
+		struct nvme_rw_command rw;
+		struct nvme_identify identify;
+		struct nvme_features features;
+		struct nvme_create_cq create_cq;
+		struct nvme_create_sq create_sq;
+		struct nvme_delete_queue delete_queue;
+		struct nvme_download_firmware dlfw;
+		struct nvme_format_cmd format;
+		struct nvme_dsm_cmd dsm;
+		struct nvme_write_zeroes_cmd write_zeroes;
+		struct nvme_zone_mgmt_send_cmd zms;
+		struct nvme_zone_mgmt_recv_cmd zmr;
+		struct nvme_abort_cmd abort;
+		struct nvme_get_log_page_command get_log_page;
+		struct nvmf_common_command fabrics;
+		struct nvmf_connect_command connect;
+		struct nvmf_property_set_command prop_set;
+		struct nvmf_property_get_command prop_get;
+		struct nvme_dbbuf dbbuf;
+		struct nvme_directive_cmd directive;
+	};
 };
 
-/*
- * is_64bit_reg - It checks whether given offset of the controller register is
- *                64bit or not.
- * @offset: offset of controller register field in bytes
- *
- * It gives true if given offset is 64bit register, otherwise it returns false.
- *
- * Notes:  This function does not care about transport so that the offset is
- * not going to be checked inside of this function for the unsupported fields
- * in a specific transport.  For example, BPMBL(Boot Partition Memory Buffer
- * Location) register is not supported by fabrics, but it can be chcked here.
- */
-static inline bool is_64bit_reg(__u32 offset)
+static inline bool nvme_is_fabrics(struct nvme_command *cmd)
 {
-	if (offset == NVME_REG_CAP ||
-			offset == NVME_REG_ASQ ||
-			offset == NVME_REG_ACQ ||
-			offset == NVME_REG_BPMBL)
-		return true;
-
-	return false;
+	return cmd->common.opcode == nvme_fabrics_command;
 }
 
-enum {
-	NVME_SCT_GENERIC		= 0x0,
-	NVME_SCT_CMD_SPECIFIC		= 0x1,
-	NVME_SCT_MEDIA			= 0x2,
-};
+struct nvme_error_slot {
+	__le64		error_count;
+	__le16		sqid;
+	__le16		cmdid;
+	__le16		status_field;
+	__le16		param_error_location;
+	__le64		lba;
+	__le32		nsid;
+	__u8		vs;
+	__u8		resv[3];
+	__le64		cs;
+	__u8		resv2[24];
+};
+
+static inline bool nvme_is_write(struct nvme_command *cmd)
+{
+	/*
+	 * What a mess...
+	 *
+	 * Why can't we simply have a Fabrics In and Fabrics out command?
+	 */
+	if (unlikely(nvme_is_fabrics(cmd)))
+		return cmd->fabrics.fctype & 1;
+	return cmd->common.opcode & 1;
+}
 
 enum {
 	/*
@@ -1514,20 +2151,21 @@ enum {
 	NVME_SC_SGL_INVALID_TYPE	= 0x11,
 	NVME_SC_CMB_INVALID_USE		= 0x12,
 	NVME_SC_PRP_INVALID_OFFSET	= 0x13,
-	NVME_SC_ATOMIC_WRITE_UNIT_EXCEEDED= 0x14,
-	NVME_SC_OPERATION_DENIED	= 0x15,
+	NVME_SC_ATOMIC_WU_EXCEEDED	= 0x14,
+	NVME_SC_OP_DENIED		= 0x15,
 	NVME_SC_SGL_INVALID_OFFSET	= 0x16,
-
-	NVME_SC_INCONSISTENT_HOST_ID= 0x18,
-	NVME_SC_KEEP_ALIVE_EXPIRED	= 0x19,
-	NVME_SC_KEEP_ALIVE_INVALID	= 0x1A,
-	NVME_SC_PREEMPT_ABORT		= 0x1B,
+	NVME_SC_RESERVED		= 0x17,
+	NVME_SC_HOST_ID_INCONSIST	= 0x18,
+	NVME_SC_KA_TIMEOUT_EXPIRED	= 0x19,
+	NVME_SC_KA_TIMEOUT_INVALID	= 0x1A,
+	NVME_SC_ABORTED_PREEMPT_ABORT	= 0x1B,
 	NVME_SC_SANITIZE_FAILED		= 0x1C,
 	NVME_SC_SANITIZE_IN_PROGRESS	= 0x1D,
-
+	NVME_SC_SGL_INVALID_GRANULARITY	= 0x1E,
+	NVME_SC_CMD_NOT_SUP_CMB_QUEUE	= 0x1F,
 	NVME_SC_NS_WRITE_PROTECTED	= 0x20,
 	NVME_SC_CMD_INTERRUPTED		= 0x21,
-	NVME_SC_TRANSIENT_TRANSPORT	= 0x22,	
+	NVME_SC_TRANSIENT_TR_ERR	= 0x22,
 
 	NVME_SC_LBA_RANGE		= 0x80,
 	NVME_SC_CAP_EXCEEDED		= 0x81,
@@ -1566,23 +2204,23 @@ enum {
 	NVME_SC_NS_NOT_ATTACHED		= 0x11a,
 	NVME_SC_THIN_PROV_NOT_SUPP	= 0x11b,
 	NVME_SC_CTRL_LIST_INVALID	= 0x11c,
-	NVME_SC_DEVICE_SELF_TEST_IN_PROGRESS= 0x11d,
+	NVME_SC_SELT_TEST_IN_PROGRESS	= 0x11d,
 	NVME_SC_BP_WRITE_PROHIBITED	= 0x11e,
-	NVME_SC_INVALID_CTRL_ID		= 0x11f,
-	NVME_SC_INVALID_SECONDARY_CTRL_STATE= 0x120,
-	NVME_SC_INVALID_NUM_CTRL_RESOURCE	= 0x121,
-	NVME_SC_INVALID_RESOURCE_ID	= 0x122,
+	NVME_SC_CTRL_ID_INVALID		= 0x11f,
+	NVME_SC_SEC_CTRL_STATE_INVALID	= 0x120,
+	NVME_SC_CTRL_RES_NUM_INVALID	= 0x121,
+	NVME_SC_RES_ID_INVALID		= 0x122,
 	NVME_SC_PMR_SAN_PROHIBITED	= 0x123,
-	NVME_SC_ANA_INVALID_GROUP_ID= 0x124,
-	NVME_SC_ANA_ATTACH_FAIL		= 0x125,
+	NVME_SC_ANA_GROUP_ID_INVALID	= 0x124,
+	NVME_SC_ANA_ATTACH_FAILED	= 0x125,
 
 	/*
 	 * Command Set Specific - Namespace Types commands:
 	 */
-	NVME_SC_IOCS_NOT_SUPPORTED		= 0x129,
-	NVME_SC_IOCS_NOT_ENABLED		= 0x12A,
-	NVME_SC_IOCS_COMBINATION_REJECTED	= 0x12B,
-	NVME_SC_INVALID_IOCS			= 0x12C,
+	NVME_SC_IOCS_NOT_SUPPORTED	= 0x129,
+	NVME_SC_IOCS_NOT_ENABLED	= 0x12a,
+	NVME_SC_IOCS_COMBINATION_REJ	= 0x12b,
+	NVME_SC_INVALID_IOCS		= 0x12c,
 
 	/*
 	 * I/O Command Set Specific - NVM commands:
@@ -1590,7 +2228,7 @@ enum {
 	NVME_SC_BAD_ATTRIBUTES		= 0x180,
 	NVME_SC_INVALID_PI		= 0x181,
 	NVME_SC_READ_ONLY		= 0x182,
-	NVME_SC_CMD_SIZE_LIMIT_EXCEEDED = 0x183,
+	NVME_SC_ONCS_NOT_SUPPORTED	= 0x183,
 
 	/*
 	 * I/O Command Set Specific - Fabrics commands:
@@ -1605,16 +2243,16 @@ enum {
 	NVME_SC_AUTH_REQUIRED		= 0x191,
 
 	/*
-	 * I/O Command Set Specific - Zoned Namespace commands:
+	 * I/O Command Set Specific - Zoned commands:
 	 */
-	NVME_SC_ZONE_BOUNDARY_ERROR		= 0x1B8,
-	NVME_SC_ZONE_IS_FULL			= 0x1B9,
-	NVME_SC_ZONE_IS_READ_ONLY		= 0x1BA,
-	NVME_SC_ZONE_IS_OFFLINE			= 0x1BB,
-	NVME_SC_ZONE_INVALID_WRITE		= 0x1BC,
-	NVME_SC_TOO_MANY_ACTIVE_ZONES		= 0x1BD,
-	NVME_SC_TOO_MANY_OPEN_ZONES		= 0x1BE,
-	NVME_SC_ZONE_INVALID_STATE_TRANSITION	= 0x1BF,
+	NVME_SC_ZONE_BOUNDARY_ERROR	= 0x1b8,
+	NVME_SC_ZONE_FULL		= 0x1b9,
+	NVME_SC_ZONE_READ_ONLY		= 0x1ba,
+	NVME_SC_ZONE_OFFLINE		= 0x1bb,
+	NVME_SC_ZONE_INVALID_WRITE	= 0x1bc,
+	NVME_SC_ZONE_TOO_MANY_ACTIVE	= 0x1bd,
+	NVME_SC_ZONE_TOO_MANY_OPEN	= 0x1be,
+	NVME_SC_ZONE_INVALID_TRANSITION	= 0x1bf,
 
 	/*
 	 * Media and Data Integrity Errors:
@@ -1634,11 +2272,28 @@ enum {
 	NVME_SC_ANA_PERSISTENT_LOSS	= 0x301,
 	NVME_SC_ANA_INACCESSIBLE	= 0x302,
 	NVME_SC_ANA_TRANSITION		= 0x303,
+	NVME_SC_HOST_PATH_ERROR		= 0x370,
+	NVME_SC_HOST_ABORTED_CMD	= 0x371,
 
 	NVME_SC_CRD			= 0x1800,
 	NVME_SC_DNR			= 0x4000,
 };
 
+struct nvme_completion {
+	/*
+	 * Used by Admin and Fabrics commands to return data:
+	 */
+	union nvme_result {
+		__le16	u16;
+		__le32	u32;
+		__le64	u64;
+	} result;
+	__le16	sq_head;	/* how much of this queue may be reclaimed */
+	__le16	sq_id;		/* submission queue that generated this entry */
+	__u16	command_id;	/* of the command which completed */
+	__le16	status;		/* did the command fail, and if so, why? */
+};
+
 #define NVME_VS(major, minor, tertiary) \
 	(((major) << 16) | ((minor) << 8) | (tertiary))
 
@@ -1646,139 +2301,4 @@ enum {
 #define NVME_MINOR(ver)		(((ver) >> 8) & 0xff)
 #define NVME_TERTIARY(ver)	((ver) & 0xff)
 
-
-/**
- * struct nvme_zns_lbafe -
- * zsze:
- * zdes:
- */
-struct nvme_zns_lbafe {
-	__le64	zsze;
-	__u8	zdes;
-	__u8	rsvd9[7];
-};
-
-/**
- * struct nvme_zns_id_ns -
- * @zoc:
- * @ozcs:
- * @mar:
- * @mor:
- * @rrl:
- * @frl:
- * @lbafe:
- * @vs:
- */
-struct nvme_zns_id_ns {
-	__le16			zoc;
-	__le16			ozcs;
-	__le32			mar;
-	__le32			mor;
-	__le32			rrl;
-	__le32			frl;
-	__u8			rsvd20[2796];
-	struct nvme_zns_lbafe	lbafe[16];
-	__u8			rsvd3072[768];
-	__u8			vs[256];
-};
-
-/**
- * struct nvme_zns_id_ctrl -
- * @zasl:
- */
-struct nvme_zns_id_ctrl {
-	__u8	zasl;
-	__u8	rsvd1[4095];
-};
-
-#define NVME_ZNS_CHANGED_ZONES_MAX	511
-
-/**
- * struct nvme_zns_changed_zone_log - ZNS Changed Zone List log
- * @nrzid:
- * @zid:
- */
-struct nvme_zns_changed_zone_log {
-	__le16		nrzid;
-	__u8		rsvd2[6];
-	__le64		zid[NVME_ZNS_CHANGED_ZONES_MAX];
-};
-
-/**
- * enum nvme_zns_zt -
- */
-enum nvme_zns_zt {
-	NVME_ZONE_TYPE_SEQWRITE_REQ	= 0x2,
-};
-
-/**
- * enum nvme_zns_za -
- */
-enum nvme_zns_za {
-	NVME_ZNS_ZA_ZFC			= 1 << 0,
-	NVME_ZNS_ZA_FZR			= 1 << 1,
-	NVME_ZNS_ZA_RZR			= 1 << 2,
-	NVME_ZNS_ZA_ZDEV		= 1 << 7,
-};
-
-/**
- * enum nvme_zns_zs -
- */
-enum nvme_zns_zs {
-	NVME_ZNS_ZS_EMPTY		= 0x1,
-	NVME_ZNS_ZS_IMPL_OPEN		= 0x2,
-	NVME_ZNS_ZS_EXPL_OPEN		= 0x3,
-	NVME_ZNS_ZS_CLOSED		= 0x4,
-	NVME_ZNS_ZS_READ_ONLY		= 0xd,
-	NVME_ZNS_ZS_FULL		= 0xe,
-	NVME_ZNS_ZS_OFFLINE		= 0xf,
-};
-
-/**
- * struct nvme_zns_desc -
- */
-struct nvme_zns_desc {
-	__u8	zt;
-	__u8	zs;
-	__u8	za;
-	__u8	rsvd3[5];
-	__le64	zcap;
-	__le64	zslba;
-	__le64	wp;
-	__u8	rsvd32[32];
-};
-
-/**
- * struct nvme_zone_report -
- */
-struct nvme_zone_report {
-	__le64			nr_zones;
-	__u8			resv8[56];
-	struct nvme_zns_desc	entries[];
-};
-
-enum nvme_zns_send_action {
-	NVME_ZNS_ZSA_CLOSE		= 0x1,
-	NVME_ZNS_ZSA_FINISH		= 0x2,
-	NVME_ZNS_ZSA_OPEN		= 0x3,
-	NVME_ZNS_ZSA_RESET		= 0x4,
-	NVME_ZNS_ZSA_OFFLINE		= 0x5,
-	NVME_ZNS_ZSA_SET_DESC_EXT	= 0x10,
-};
-
-enum nvme_zns_recv_action {
-	NVME_ZNS_ZRA_REPORT_ZONES		= 0x0,
-	NVME_ZNS_ZRA_EXTENDED_REPORT_ZONES	= 0x1,
-};
-
-enum nvme_zns_report_options {
-	NVME_ZNS_ZRAS_REPORT_ALL		= 0x0,
-	NVME_ZNS_ZRAS_REPORT_EMPTY		= 0x1,
-	NVME_ZNS_ZRAS_REPORT_IMPL_OPENED	= 0x2,
-	NVME_ZNS_ZRAS_REPORT_EXPL_OPENED	= 0x3,
-	NVME_ZNS_ZRAS_REPORT_CLOSED		= 0x4,
-	NVME_ZNS_ZRAS_REPORT_FULL		= 0x5,
-	NVME_ZNS_ZRAS_REPORT_READ_ONLY		= 0x6,
-	NVME_ZNS_ZRAS_REPORT_OFFLINE		= 0x7,
-};
 #endif /* _LINUX_NVME_H */
diff --git a/nvme-ioctl.c b/nvme-ioctl.c
index a99d490..ba72f4b 100644
--- a/nvme-ioctl.c
+++ b/nvme-ioctl.c
@@ -417,7 +417,7 @@ int nvme_identify_ns_list_csi(int fd, __u32 nsid, __u8 csi, bool all, void *data
 	int cns;
 
 	if (csi) {
-		cns = all ? NVME_ID_CNS_CSI_NS_PRESENT_LIST : NVME_ID_CNS_CSI_NS_ACTIVE_LIST;
+		cns = all ? NVME_ID_CNS_NS_PRESENT_LIST : NVME_ID_CNS_CS_NS_ACTIVE_LIST;
 	} else {
 		cns = all ? NVME_ID_CNS_NS_PRESENT_LIST : NVME_ID_CNS_NS_ACTIVE_LIST;
 	}
@@ -465,12 +465,12 @@ int nvme_identify_uuid(int fd, void *data)
 
 int nvme_zns_identify_ns(int fd, __u32 nsid, void *data)
 {
-	return nvme_identify13(fd, nsid, NVME_ID_CNS_CSI_ID_NS, 2 << 24, data);
+	return nvme_identify13(fd, nsid, NVME_ID_CNS_CS_NS, 2 << 24, data);
 }
 
 int nvme_zns_identify_ctrl(int fd, void *data)
 {
-	return nvme_identify13(fd, 0, NVME_ID_CNS_CSI_ID_CTRL, 2 << 24, data);
+	return nvme_identify13(fd, 0, NVME_ID_CNS_CS_CTRL, 2 << 24, data);
 }
 
 int nvme_identify_iocs(int fd, __u16 cntid, void *data)
@@ -987,7 +987,7 @@ int nvme_zns_mgmt_send(int fd, __u32 nsid, __u64 slba, bool select_all,
 	__u32 cdw13 = zsa | (!!select_all) << 8;
 
 	struct nvme_passthru_cmd cmd = {
-		.opcode		= nvme_zns_cmd_mgmt_send,
+		.opcode		= nvme_cmd_zone_mgmt_send,
 		.nsid		= nsid,
 		.cdw10		= cdw10,
 		.cdw11		= cdw11,
@@ -1009,7 +1009,7 @@ int nvme_zns_mgmt_recv(int fd, __u32 nsid, __u64 slba,
 	__u32 cdw13 = zra | zrasf << 8 | zras_feat << 16;
 
 	struct nvme_passthru_cmd cmd = {
-		.opcode		= nvme_zns_cmd_mgmt_recv,
+		.opcode		= nvme_cmd_zone_mgmt_recv,
 		.nsid		= nsid,
 		.cdw10		= cdw10,
 		.cdw11		= cdw11,
@@ -1049,7 +1049,7 @@ int nvme_zns_append(int fd, __u32 nsid, __u64 zslba, __u16 nlb, __u16 control,
 	__u32 cdw15 = lbat | (lbatm << 16);
 
 	struct nvme_passthru_cmd64 cmd = {
-		.opcode		= nvme_zns_cmd_append,
+		.opcode		= nvme_cmd_zone_append,
 		.nsid		= nsid,
 		.cdw10		= cdw10,
 		.cdw11		= cdw11,
diff --git a/nvme-print.c b/nvme-print.c
index 09ada75..b48caa3 100644
--- a/nvme-print.c
+++ b/nvme-print.c
@@ -301,7 +301,7 @@ static void json_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode,
 	json_object_add_value_int(root, "vwc", ctrl->vwc);
 	json_object_add_value_int(root, "awun", le16_to_cpu(ctrl->awun));
 	json_object_add_value_int(root, "awupf", le16_to_cpu(ctrl->awupf));
-	json_object_add_value_int(root, "icsvscc", ctrl->icsvscc);
+	json_object_add_value_int(root, "nvscc", ctrl->nvscc);
 	json_object_add_value_int(root, "nwpc", ctrl->nwpc);
 	json_object_add_value_int(root, "acwu", le16_to_cpu(ctrl->acwu));
 	json_object_add_value_int(root, "ocfs", le16_to_cpu(ctrl->ocfs));
@@ -2881,10 +2881,10 @@ static void nvme_show_id_ctrl_vwc(__u8 vwc)
 	printf("\n");
 }
 
-static void nvme_show_id_ctrl_icsvscc(__u8 icsvscc)
+static void nvme_show_id_ctrl_nvscc(__u8 nvscc)
 {
-	__u8 rsvd = (icsvscc & 0xFE) >> 1;
-	__u8 fmt = icsvscc & 0x1;
+	__u8 rsvd = (nvscc & 0xFE) >> 1;
+	__u8 fmt = nvscc & 0x1;
 	if (rsvd)
 		printf("  [7:1] : %#x\tReserved\n", rsvd);
 	printf("  [0:0] : %#x\tNVM Vendor Specific Commands uses %s Format\n",
@@ -3572,9 +3572,9 @@ void __nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, enum nvme_print_flags flags,
 		nvme_show_id_ctrl_vwc(ctrl->vwc);
 	printf("awun      : %d\n", le16_to_cpu(ctrl->awun));
 	printf("awupf     : %d\n", le16_to_cpu(ctrl->awupf));
-	printf("icsvscc     : %d\n", ctrl->icsvscc);
+	printf("nvscc     : %d\n", ctrl->nvscc);
 	if (human)
-		nvme_show_id_ctrl_icsvscc(ctrl->icsvscc);
+		nvme_show_id_ctrl_nvscc(ctrl->nvscc);
 	printf("nwpc      : %d\n", ctrl->nwpc);
 	if (human)
 		nvme_show_id_ctrl_nwpc(ctrl->nwpc);
@@ -3630,7 +3630,7 @@ void nvme_show_zns_id_ctrl(struct nvme_zns_id_ctrl *ctrl, unsigned int mode)
 	printf("zasl    : %u\n", ctrl->zasl);
 }
 
-void json_nvme_zns_id_ns(struct nvme_zns_id_ns *ns,
+void json_nvme_zns_id_ns(struct nvme_id_ns_zns *ns,
 	struct nvme_id_ns *id_ns, unsigned long flags)
 {
 	struct json_object *root;
@@ -3689,7 +3689,7 @@ static void show_nvme_id_ns_zoned_ozcs(__le16 ns_ozcs)
 		razb, razb ? "Yes" : "No");
 }
 
-void nvme_show_zns_id_ns(struct nvme_zns_id_ns *ns,
+void nvme_show_zns_id_ns(struct nvme_id_ns_zns *ns,
 	struct nvme_id_ns *id_ns, unsigned long flags)
 {
 	int human = flags & VERBOSE, vs = flags & VS;
@@ -3823,7 +3823,7 @@ void nvme_show_zns_report_zones(void *report, __u32 descs,
 	__u8 ext_size, __u32 report_size, unsigned long flags)
 {
 	struct nvme_zone_report *r = report;
-	struct nvme_zns_desc *desc;
+	struct nvme_zone_descriptor *desc;
 	int i;
 
 	__u64 nr_zones = le64_to_cpu(r->nr_zones);
@@ -3836,7 +3836,7 @@ void nvme_show_zns_report_zones(void *report, __u32 descs,
 
 	printf("nr_zones: %"PRIu64"\n", (uint64_t)le64_to_cpu(r->nr_zones));
 	for (i = 0; i < descs; i++) {
-		desc = (struct nvme_zns_desc *)
+		desc = (struct nvme_zone_descriptor *)
 			(report + sizeof(*r) + i * (sizeof(*desc) + ext_size));
 		printf("SLBA: 0x%-8"PRIx64" WP: 0x%-8"PRIx64" Cap: 0x%-8"PRIx64" State: %-12s Type: %-14s Attrs: 0x%-x\n",
 		(uint64_t)le64_to_cpu(desc->zslba), (uint64_t)le64_to_cpu(desc->wp),
@@ -4711,10 +4711,9 @@ void nvme_show_sanitize_log(struct nvme_sanitize_log_page *sanitize,
 		le32_to_cpu(sanitize->est_crypto_erase_time_with_no_deallocate));
 }
 
-const char *nvme_feature_to_string(enum nvme_feat feature)
+const char *nvme_feature_to_string(__u8 feature)
 {
 	switch (feature) {
-	case NVME_FEAT_NONE:		return "None";
 	case NVME_FEAT_ARBITRATION:	return "Arbitration";
 	case NVME_FEAT_POWER_MGMT:	return "Power Management";
 	case NVME_FEAT_LBA_RANGE:	return "LBA Range Type";
@@ -4835,19 +4834,19 @@ const char *nvme_status_to_string(__u32 status)
 		return "CMB_INVALID_USE: The attempted use of the Controller Memory Buffer is not supported by the controller.";
 	case NVME_SC_PRP_INVALID_OFFSET:
 		return "PRP_INVALID_OFFSET: The Offset field for a PRP entry is invalid.";
-	case NVME_SC_ATOMIC_WRITE_UNIT_EXCEEDED:
+	case NVME_SC_ATOMIC_WU_EXCEEDED:
 		return "ATOMIC_WRITE_UNIT_EXCEEDED: The length specified exceeds the atomic write unit size.";
-	case NVME_SC_OPERATION_DENIED:
+	case NVME_SC_OP_DENIED:
 		return "OPERATION_DENIED: The command was denied due to lack of access rights.";
 	case NVME_SC_SGL_INVALID_OFFSET:
 		return "SGL_INVALID_OFFSET: The offset specified in a descriptor is invalid.";
-	case NVME_SC_INCONSISTENT_HOST_ID:
+	case NVME_SC_HOST_ID_INCONSIST:
 		return "INCONSISTENT_HOST_ID: The NVM subsystem detected the simultaneous use of 64-bit and 128-bit Host Identifier values on different controllers.";
-	case NVME_SC_KEEP_ALIVE_EXPIRED:
+	case NVME_SC_KA_TIMEOUT_EXPIRED:
 		return "KEEP_ALIVE_EXPIRED: The Keep Alive Timer expired.";
-	case NVME_SC_KEEP_ALIVE_INVALID:
+	case NVME_SC_KA_TIMEOUT_INVALID:
 		return "KEEP_ALIVE_INVALID: The Keep Alive Timeout value specified is invalid.";
-	case NVME_SC_PREEMPT_ABORT:
+	case NVME_SC_ABORTED_PREEMPT_ABORT:
 		return "PREEMPT_ABORT: The command was aborted due to a Reservation Acquire command with the Reservation Acquire Action (RACQA) set to 010b (Preempt and Abort).";
 	case NVME_SC_SANITIZE_FAILED:
 		return "SANITIZE_FAILED: The most recent sanitize operation failed and no recovery actions has been successfully completed";
@@ -4857,7 +4856,7 @@ const char *nvme_status_to_string(__u32 status)
 		return "IOCS_NOT_SUPPORTED: The I/O command set is not supported";
 	case NVME_SC_IOCS_NOT_ENABLED:
 		return "IOCS_NOT_ENABLED: The I/O command set is not enabled";
-	case NVME_SC_IOCS_COMBINATION_REJECTED:
+	case NVME_SC_IOCS_COMBINATION_REJ:
 		return "IOCS_COMBINATION_REJECTED: The I/O command set combination is rejected";
 	case NVME_SC_INVALID_IOCS:
 		return "INVALID_IOCS: the I/O command set is invalid";
@@ -4865,7 +4864,7 @@ const char *nvme_status_to_string(__u32 status)
 		return "LBA_RANGE: The command references a LBA that exceeds the size of the namespace";
 	case NVME_SC_NS_WRITE_PROTECTED:
 		return "NS_WRITE_PROTECTED: The command is prohibited while the namespace is write protected by the host.";
-	case NVME_SC_TRANSIENT_TRANSPORT:
+	case NVME_SC_TRANSIENT_TR_ERR:
 		return "TRANSIENT_TRANSPORT: A transient transport error was detected.";
 	case NVME_SC_CAP_EXCEEDED:
 		return "CAP_EXCEEDED: The execution of the command has caused the capacity of the namespace to be exceeded";
@@ -4877,19 +4876,19 @@ const char *nvme_status_to_string(__u32 status)
 		return "FORMAT_IN_PROGRESS: A Format NVM command is in progress on the namespace.";
 	case NVME_SC_ZONE_BOUNDARY_ERROR:
 		return "ZONE_BOUNDARY_ERROR: Invalid Zone Boundary crossing";
-	case NVME_SC_ZONE_IS_FULL:
+	case NVME_SC_ZONE_FULL:
 		return "ZONE_IS_FULL: The accessed zone is in ZSF:Full state";
-	case NVME_SC_ZONE_IS_READ_ONLY:
+	case NVME_SC_ZONE_READ_ONLY:
 		return "ZONE_IS_READ_ONLY: The accessed zone is in ZSRO:Read Only state";
-	case NVME_SC_ZONE_IS_OFFLINE:
+	case NVME_SC_ZONE_OFFLINE:
 		return "ZONE_IS_OFFLINE: The access zone is in ZSO:Offline state";
 	case NVME_SC_ZONE_INVALID_WRITE:
 		return "ZONE_INVALID_WRITE: The write to zone was not at the write pointer offset";
-	case NVME_SC_TOO_MANY_ACTIVE_ZONES:
+	case NVME_SC_ZONE_TOO_MANY_ACTIVE:
 		return "TOO_MANY_ACTIVE_ZONES: The controller does not allow additional active zones";
-	case NVME_SC_TOO_MANY_OPEN_ZONES:
+	case NVME_SC_ZONE_TOO_MANY_OPEN:
 		return "TOO_MANY_OPEN_ZONES: The controller does not allow additional open zones";
-	case NVME_SC_ZONE_INVALID_STATE_TRANSITION:
+	case NVME_SC_ZONE_INVALID_TRANSITION:
 		return "INVALID_ZONE_STATE_TRANSITION: The zone state change was invalid";
 	case NVME_SC_CQ_INVALID:
 		return "CQ_INVALID: The Completion Queue identifier specified in the command does not exist";
@@ -4947,26 +4946,24 @@ const char *nvme_status_to_string(__u32 status)
 		return "THIN_PROVISIONING_NOT_SUPPORTED: Thin provisioning is not supported by the controller";
 	case NVME_SC_CTRL_LIST_INVALID:
 		return "CONTROLLER_LIST_INVALID: The controller list provided is invalid";
-	case NVME_SC_DEVICE_SELF_TEST_IN_PROGRESS:
+	case NVME_SC_SELT_TEST_IN_PROGRESS:
 		return "DEVICE_SELF_TEST_IN_PROGRESS: The controller or NVM subsystem already has a device self-test operation in process.";
 	case NVME_SC_BP_WRITE_PROHIBITED:
 		return "BOOT PARTITION WRITE PROHIBITED: The command is trying to modify a Boot Partition while it is locked";
-	case NVME_SC_INVALID_CTRL_ID:
+	case NVME_SC_CTRL_ID_INVALID:
 		return "INVALID_CTRL_ID: An invalid Controller Identifier was specified.";
-	case NVME_SC_INVALID_SECONDARY_CTRL_STATE:
+	case NVME_SC_SEC_CTRL_STATE_INVALID:
 		return "INVALID_SECONDARY_CTRL_STATE: The action requested for the secondary controller is invalid based on the current state of the secondary controller and its primary controller.";
-	case NVME_SC_INVALID_NUM_CTRL_RESOURCE:
+	case NVME_SC_CTRL_RES_NUM_INVALID:
 		return "INVALID_NUM_CTRL_RESOURCE: The specified number of Flexible Resources is invalid";
-	case NVME_SC_INVALID_RESOURCE_ID:
+	case NVME_SC_RES_ID_INVALID:
 		return "INVALID_RESOURCE_ID: At least one of the specified resource identifiers was invalid";
-	case NVME_SC_ANA_INVALID_GROUP_ID:
+	case NVME_SC_ANA_GROUP_ID_INVALID:
 		return "ANA_INVALID_GROUP_ID: The specified ANA Group Identifier (ANAGRPID) is not supported in the submitted command.";
-	case NVME_SC_ANA_ATTACH_FAIL:
+	case NVME_SC_ANA_ATTACH_FAILED:
 		return "ANA_ATTACH_FAIL: The controller is not attached to the namespace as a result of an ANA condition";
 	case NVME_SC_BAD_ATTRIBUTES:
 		return "BAD_ATTRIBUTES: Bad attributes were given";
-	case NVME_SC_CMD_SIZE_LIMIT_EXCEEDED:
-		return "CMD_SIZE_LIMIT_EXCEEDED: Command size limit exceeded";
 	case NVME_SC_WRITE_FAULT:
 		return "WRITE_FAULT: The write data could not be committed to the media";
 	case NVME_SC_READ_ERROR:
@@ -5231,7 +5228,7 @@ static void nvme_show_plm_config(struct nvme_plm_config *plmcfg)
 	printf("\tDTWIN Time Threshold  :%"PRIu64"\n", le64_to_cpu(plmcfg->dtwin_time_thresh));
 }
 
-void nvme_feature_show_fields(enum nvme_feat fid, unsigned int result, unsigned char *buf)
+void nvme_feature_show_fields(__u8 fid, unsigned int result, unsigned char *buf)
 {
 	__u8 field;
 	uint64_t ull;
@@ -5351,7 +5348,6 @@ void nvme_feature_show_fields(enum nvme_feat fid, unsigned int result, unsigned
 	case NVME_FEAT_HOST_BEHAVIOR:
 		printf("\tHost Behavior Support: %s\n", (buf[0] & 0x1) ? "True" : "False");
 		break;
-	case NVME_FEAT_NONE:
 	case NVME_FEAT_SANITIZE:
 	case NVME_FEAT_RRL:
 		printf("\t%s: to be implemented\n", nvme_feature_to_string(fid));
diff --git a/nvme-print.h b/nvme-print.h
index 368434c..cfea19f 100644
--- a/nvme-print.h
+++ b/nvme-print.h
@@ -73,13 +73,13 @@ void nvme_show_id_uuid_list(const struct nvme_id_uuid_list *uuid_list,
 	enum nvme_print_flags flags);
 void nvme_show_id_iocs(struct nvme_id_iocs *iocs);
 
-void nvme_feature_show_fields(enum nvme_feat fid, unsigned int result, unsigned char *buf);
+void nvme_feature_show_fields(__u8 fid, unsigned int result, unsigned char *buf);
 void nvme_directive_show(__u8 type, __u8 oper, __u16 spec, __u32 nsid, __u32 result,
 	void *buf, __u32 len, enum nvme_print_flags flags);
 void nvme_show_select_result(__u32 result);
 
 void nvme_show_zns_id_ctrl(struct nvme_zns_id_ctrl *ctrl, unsigned int mode);
-void nvme_show_zns_id_ns(struct nvme_zns_id_ns *ns,
+void nvme_show_zns_id_ns(struct nvme_id_ns_zns *ns,
 	struct nvme_id_ns *id_ns, unsigned long flags);
 void nvme_show_zns_changed( struct nvme_zns_changed_zone_log *log,
 	unsigned long flags);
@@ -88,7 +88,7 @@ void nvme_show_zns_report_zones(void *report, __u32 descs,
 
 const char *nvme_status_to_string(__u32 status);
 const char *nvme_select_to_string(int sel);
-const char *nvme_feature_to_string(enum nvme_feat feature);
+const char *nvme_feature_to_string(__u8 feature);
 const char *nvme_register_to_string(int reg);
 
 #endif
diff --git a/nvme-status.c b/nvme-status.c
index 7821de2..71f7b50 100644
--- a/nvme-status.c
+++ b/nvme-status.c
@@ -45,7 +45,7 @@ static inline __u8 nvme_generic_status_to_errno(__u16 status)
 		return EREMOTEIO;
 	case NVME_SC_CAP_EXCEEDED:
 		return ENOSPC;
-	case NVME_SC_OPERATION_DENIED:
+	case NVME_SC_OP_DENIED:
 		return EPERM;
 	}
 
@@ -69,11 +69,11 @@ static inline __u8 nvme_cmd_specific_status_to_errno(__u16 status)
 	case NVME_SC_CTRL_LIST_INVALID:
 	case NVME_SC_BAD_ATTRIBUTES:
 	case NVME_SC_INVALID_PI:
-	case NVME_SC_INVALID_CTRL_ID:
-	case NVME_SC_INVALID_SECONDARY_CTRL_STATE:
-	case NVME_SC_INVALID_NUM_CTRL_RESOURCE:
-	case NVME_SC_INVALID_RESOURCE_ID:
-	case NVME_SC_ANA_INVALID_GROUP_ID:
+	case NVME_SC_CTRL_ID_INVALID:
+	case NVME_SC_SEC_CTRL_STATE_INVALID:
+	case NVME_SC_CTRL_RES_NUM_INVALID:
+	case NVME_SC_RES_ID_INVALID:
+	case NVME_SC_ANA_GROUP_ID_INVALID:
 		return EINVAL;
 	case NVME_SC_ABORT_LIMIT:
 	case NVME_SC_ASYNC_LIMIT:
@@ -98,7 +98,7 @@ static inline __u8 nvme_cmd_specific_status_to_errno(__u16 status)
 		return EALREADY;
 	case NVME_SC_THIN_PROV_NOT_SUPP:
 		return EOPNOTSUPP;
-	case NVME_SC_DEVICE_SELF_TEST_IN_PROGRESS:
+	case NVME_SC_SELT_TEST_IN_PROGRESS:
 		return EINPROGRESS;
 	}
 
diff --git a/nvme.h b/nvme.h
index 3fb1060..a2373f5 100644
--- a/nvme.h
+++ b/nvme.h
@@ -26,6 +26,29 @@
 #include "util/argconfig.h"
 #include "linux/nvme.h"
 
+/*
+ * is_64bit_reg - It checks whether given offset of the controller register is
+ *                64bit or not.
+ * @offset: offset of controller register field in bytes
+ *
+ * It gives true if given offset is 64bit register, otherwise it returns false.
+ *
+ * Notes:  This function does not care about transport so that the offset is
+ * not going to be checked inside of this function for the unsupported fields
+ * in a specific transport.  For example, BPMBL(Boot Partition Memory Buffer
+ * Location) register is not supported by fabrics, but it can be chcked here.
+ */
+static inline bool is_64bit_reg(__u32 offset)
+{
+	if (offset == NVME_REG_CAP ||
+	    offset == NVME_REG_ASQ ||
+	    offset == NVME_REG_ACQ ||
+	    offset == NVME_REG_BPMBL)
+		return true;
+
+	return false;
+}
+
 enum nvme_print_flags {
 	NORMAL	= 0,
 	VERBOSE	= 1 << 0,	/* verbosely decode complex values for humans */
diff --git a/plugins/shannon/shannon-nvme.c b/plugins/shannon/shannon-nvme.c
index 46ace75..abcc9e9 100644
--- a/plugins/shannon/shannon-nvme.c
+++ b/plugins/shannon/shannon-nvme.c
@@ -182,7 +182,7 @@ static int get_additional_feature(int argc, char **argv, struct command *cmd, st
 
 	struct config {
 		__u32 namespace_id;
-		enum nvme_feat feature_id;
+		__u8  feature_id;
 		__u8  sel;
 		__u32 cdw11;
 		__u32 data_len;
@@ -192,7 +192,7 @@ static int get_additional_feature(int argc, char **argv, struct command *cmd, st
 
 	struct config cfg = {
 		.namespace_id = 1,
-		.feature_id   = NVME_FEAT_NONE,
+		.feature_id   = 0,
 		.sel          = 0,
 		.cdw11        = 0,
 		.data_len     = 0,
diff --git a/plugins/virtium/virtium-nvme.c b/plugins/virtium/virtium-nvme.c
index a194a5f..f401d1e 100644
--- a/plugins/virtium/virtium-nvme.c
+++ b/plugins/virtium/virtium-nvme.c
@@ -883,7 +883,7 @@ static void vt_parse_detail_identify(const struct nvme_id_ctrl *ctrl)
 	vt_convert_data_buffer_to_hex_string(&buf[528], 2, true, s);
 	printf("    \"Atomic Write Unit Power Fail\":\"%sh\",\n", s);
 
-	temp = ctrl->icsvscc;
+	temp = ctrl->nvscc;
 	printf("    \"NVM Vendor Specific Command Configuration\":{\n");
 	vt_convert_data_buffer_to_hex_string(&buf[530], 1, true, s);
 	printf("        \"Value\":\"%sh\",\n", s);
diff --git a/plugins/zns/zns.c b/plugins/zns/zns.c
index 26b3f90..df2ecec 100644
--- a/plugins/zns/zns.c
+++ b/plugins/zns/zns.c
@@ -68,7 +68,7 @@ static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plug
 	const char *human_readable = "show identify in readable format";
 
 	enum nvme_print_flags flags;
-	struct nvme_zns_id_ns ns;
+	struct nvme_id_ns_zns ns;
 	struct nvme_id_ns id_ns;
 	int fd, err = -1;
 
@@ -199,7 +199,7 @@ close_fd:
 
 static int get_zdes_bytes(int fd, __u32 nsid)
 {
-	struct nvme_zns_id_ns ns;
+	struct nvme_id_ns_zns ns;
 	struct nvme_id_ns id_ns;
 	__u8 lbaf;
 	int err;
@@ -629,7 +629,7 @@ static int report_zones(int argc, char **argv, struct command *cmd, struct plugi
 	}
 
 	report_size = sizeof(struct nvme_zone_report) + cfg.num_descs *
-		(sizeof(struct nvme_zns_desc) + cfg.num_descs * zdes);
+		(sizeof(struct nvme_zone_descriptor) + cfg.num_descs * zdes);
 
 	report = nvme_alloc(report_size, &huge);
 	if (!report) {
-- 
2.25.4



From hare at suse.de  Thu Jan 21 04:27:56 2021
From: hare at suse.de (Hannes Reinecke)
Date: Thu, 21 Jan 2021 10:27:56 +0100
Subject: [PATCH v3 3/5] nvme-fabrics: avoid double request completion for
 nvmf_fail_nonready_command
In-Reply-To: <20210121090012.GA27342@lst.de>
References: <20210121070330.19701-1-lengchao@huawei.com>
 <20210121070330.19701-4-lengchao@huawei.com>
 <fda1fdb8-8a9d-2e95-4d08-8d8ee1df450d@suse.de>
 <20210121090012.GA27342@lst.de>
Message-ID: <467a43b0-82cc-69b7-460a-413ddc8cf574@suse.de>

On 1/21/21 10:00 AM, Christoph Hellwig wrote:
> On Thu, Jan 21, 2021 at 09:58:37AM +0100, Hannes Reinecke wrote:
>> On 1/21/21 8:03 AM, Chao Leng wrote:
>>> When reconnect, the request may be completed with NVME_SC_HOST_PATH_ERROR
>>> in nvmf_fail_nonready_command. The state of request will be changed to
>>> MQ_RQ_IN_FLIGHT before call nvme_complete_rq. If free the request
>>> asynchronously such as in nvme_submit_user_cmd, in extreme scenario
>>> the request may be completed again in tear down process.
>>> nvmf_fail_nonready_command do not need calling blk_mq_start_request
>>> before complete the request. nvmf_fail_nonready_command should set
>>> the state of request to MQ_RQ_COMPLETE before complete the request.
>>>
>>
>> So what you are saying is that there is a race condition between
>> blk_mq_start_request()
>> and
>> nvme_complete_request()
> 
> Between those to a teardown that cancels all requests can come in.
> 
Doesn't nvme_complete_request() insulate against a double completion?
I seem to remember we've gone through great lengths ensuring that.

And if this is just about setting the correct error code on completion 
I'd really prefer to stick with the current code. Moving that into a 
helper is fine, but I'd rather not introduce our own code modifying 
request state.

If there really is a race condition this feels like a more generic 
problem; calling blk_mq_start_request() followed by blk_mq_end_request() 
is a quite common pattern, and from my impression the recommended way.
So if there is an issue it would need to be addressed for all drivers, 
not just some nvme-specific way.
Plus I'd like to have Jens' opinion here.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare at suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 N?rnberg
HRB 36809 (AG N?rnberg), Gesch?ftsf?hrer: Felix Imend?rffer


From hare at suse.de  Thu Jan 21 04:50:21 2021
From: hare at suse.de (Hannes Reinecke)
Date: Thu, 21 Jan 2021 10:50:21 +0100
Subject: [PATCH] nvme: do not ignore nvme status in nvme_set_queue_count()
Message-ID: <20210121095021.22807-1-hare@suse.de>

If the call to nvme_set_queue_count() fails with a status we should
not ignore it but rather pass it on to the caller.
It's then up to the transport to decide whether to ignore it
(like PCI does) or to reset the connection (as would be appropriate
for fabrics).

Signed-off-by: Hannes Reinecke <hare at suse.de>
---
 drivers/nvme/host/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index ce1b61519441..ddf32f5b4534 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -1486,7 +1486,7 @@ int nvme_set_queue_count(struct nvme_ctrl *ctrl, int *count)
 		*count = min(*count, nr_io_queues);
 	}
 
-	return 0;
+	return status;
 }
 EXPORT_SYMBOL_GPL(nvme_set_queue_count);
 
-- 
2.26.2



From axboe at kernel.dk  Thu Jan 21 07:41:42 2021
From: axboe at kernel.dk (Jens Axboe)
Date: Thu, 21 Jan 2021 05:41:42 -0700
Subject: [GIT PULL] nvme fixes for 5.11
In-Reply-To: <YAk8Kt/DRZ7T6WBl@infradead.org>
References: <YAk8Kt/DRZ7T6WBl@infradead.org>
Message-ID: <24912e65-18c1-2b15-118b-854b9d9ba658@kernel.dk>

On 1/21/21 1:32 AM, Christoph Hellwig wrote:
> git://git.infradead.org/nvme.git tags/nvme-5.11-2020-01-21

Pulled, thanks.

-- 
Jens Axboe



From Niklas.Cassel at wdc.com  Thu Jan 21 07:45:00 2021
From: Niklas.Cassel at wdc.com (Niklas Cassel)
Date: Thu, 21 Jan 2021 12:45:00 +0000
Subject: Problem with SPCC 256GB NVMe 1.3 drive - refcount_t: underflow;
 use-after-free.
In-Reply-To: <df46d7ce-ce70-1f43-0efd-7153761bcff0@comcast.net>
References: <f50bc59c-db11-bb44-55be-7b9db1119872@comcast.net>
 <BYAPR04MB49659C0F0F0E11D166B31E0586A40@BYAPR04MB4965.namprd04.prod.outlook.com>
 <a4c75497-d170-1e0f-8608-282231ff3a8e@comcast.net>
 <BYAPR04MB496542BEF594F0380F7D41CF86A20@BYAPR04MB4965.namprd04.prod.outlook.com>
 <df46d7ce-ce70-1f43-0efd-7153761bcff0@comcast.net>
Message-ID: <20210121124459.GA156577@localhost.localdomain>

On Wed, Jan 20, 2021 at 09:33:08PM -0500, Bradley Chapman wrote:
> > > > Also can you please also try the latest nvme tree branch nvme-5.11 ?
> > > > 
> > > Where do I get that code from? Is it already in the 5.11-rc tree or do I
> > > need to look somewhere else? I checked https://github.com/linux-nvme but
> > > I did not see it there.
> > Here is the link :-git://git.infradead.org/nvme.git
> > Branch 5.12.
> 
> I tried fetching the entire repo but it was huge and would have taken a long
> time, so I tried to fetch a single branch instead and got this result:
> 
> $ git clone --branch 5.12 --single-branch git://git.infradead.org/nvme.git
> Cloning into 'nvme'...
> warning: Could not find remote branch 5.12 to clone.
> fatal: Remote branch 5.12 not found in upstream origin
> 
> I haven't compiled any out-of-tree kernel code in a very long time - how
> easy is it to add this code to a kernel tree and compile it into the kernel
> once I've figured out how to get it?

Hello there,

You can see the available branches by replacing git:// with https:// i.e.:
https://git.infradead.org/nvme.git

The branch is called nvme-5.12

It is not out-of-tree kernel code, it is a subsystem git tree,
so you build the kernel like usual.

If you already have a kernel git tree somewhere,
simply add an additional remote, and it should be quick:

$ git remote add nvme git://git.infradead.org/nvme.git && git fetch nvme


Kind regards,
Niklas

From guoqing.jiang at cloud.ionos.com  Thu Jan 21 09:29:03 2021
From: guoqing.jiang at cloud.ionos.com (Guoqing Jiang)
Date: Thu, 21 Jan 2021 15:29:03 +0100
Subject: [PATCH 0/2] remove unused argument from blk_execute_rq_nowait and
 blk_execute_rq
Message-ID: <20210121142905.13089-1-guoqing.jiang@cloud.ionos.com>

Hi Jens,

This series remove unused 'q' from blk_execute_rq_nowait and blk_execute_rq.
Also update the comment for blk_execute_rq_nowait.

Thanks,
Guoqing

Guoqing Jiang (2):
  block: remove unnecessary argument from blk_execute_rq_nowait
  block: remove unnecessary argument from blk_execute_rq

 block/blk-exec.c                   | 13 +++++--------
 block/bsg.c                        |  2 +-
 block/scsi_ioctl.c                 |  6 +++---
 drivers/block/mtip32xx/mtip32xx.c  |  2 +-
 drivers/block/paride/pd.c          |  2 +-
 drivers/block/pktcdvd.c            |  2 +-
 drivers/block/sx8.c                |  4 ++--
 drivers/block/virtio_blk.c         |  2 +-
 drivers/cdrom/cdrom.c              |  2 +-
 drivers/ide/ide-atapi.c            |  2 +-
 drivers/ide/ide-cd.c               |  2 +-
 drivers/ide/ide-cd_ioctl.c         |  2 +-
 drivers/ide/ide-devsets.c          |  2 +-
 drivers/ide/ide-disk.c             |  2 +-
 drivers/ide/ide-ioctls.c           |  4 ++--
 drivers/ide/ide-park.c             |  2 +-
 drivers/ide/ide-pm.c               |  4 ++--
 drivers/ide/ide-tape.c             |  2 +-
 drivers/ide/ide-taskfile.c         |  2 +-
 drivers/mmc/core/block.c           | 10 +++++-----
 drivers/nvme/host/core.c           |  8 ++++----
 drivers/nvme/host/lightnvm.c       |  4 ++--
 drivers/nvme/host/pci.c            |  4 ++--
 drivers/nvme/target/passthru.c     |  2 +-
 drivers/scsi/scsi_error.c          |  2 +-
 drivers/scsi/scsi_lib.c            |  2 +-
 drivers/scsi/sg.c                  |  3 +--
 drivers/scsi/st.c                  |  2 +-
 drivers/target/target_core_pscsi.c |  3 +--
 fs/nfsd/blocklayout.c              |  2 +-
 include/linux/blkdev.h             |  5 ++---
 31 files changed, 50 insertions(+), 56 deletions(-)

-- 
2.17.1



From guoqing.jiang at cloud.ionos.com  Thu Jan 21 09:29:04 2021
From: guoqing.jiang at cloud.ionos.com (Guoqing Jiang)
Date: Thu, 21 Jan 2021 15:29:04 +0100
Subject: [PATCH 1/2] block: remove unnecessary argument from
 blk_execute_rq_nowait
In-Reply-To: <20210121142905.13089-1-guoqing.jiang@cloud.ionos.com>
References: <20210121142905.13089-1-guoqing.jiang@cloud.ionos.com>
Message-ID: <20210121142905.13089-2-guoqing.jiang@cloud.ionos.com>

The 'q' is not used since commit a1ce35fa4985 ("block: remove dead
elevator code"), also update the comment of the function.

Cc: target-devel at vger.kernel.org
Cc: linux-scsi at vger.kernel.org
Cc: virtualization at lists.linux-foundation.org
Cc: linux-ide at vger.kernel.org
Cc: linux-mmc at vger.kernel.org
Cc: linux-nvme at lists.infradead.org
Cc: linux-nfs at vger.kernel.org
Signed-off-by: Guoqing Jiang <guoqing.jiang at cloud.ionos.com>
---
 block/blk-exec.c                   | 10 ++++------
 drivers/block/sx8.c                |  4 ++--
 drivers/nvme/host/core.c           |  4 ++--
 drivers/nvme/host/lightnvm.c       |  2 +-
 drivers/nvme/host/pci.c            |  4 ++--
 drivers/nvme/target/passthru.c     |  2 +-
 drivers/scsi/scsi_error.c          |  2 +-
 drivers/scsi/sg.c                  |  3 +--
 drivers/scsi/st.c                  |  2 +-
 drivers/target/target_core_pscsi.c |  3 +--
 include/linux/blkdev.h             |  2 +-
 11 files changed, 17 insertions(+), 21 deletions(-)

diff --git a/block/blk-exec.c b/block/blk-exec.c
index 85324d53d072..2e37e85456fb 100644
--- a/block/blk-exec.c
+++ b/block/blk-exec.c
@@ -31,8 +31,7 @@ static void blk_end_sync_rq(struct request *rq, blk_status_t error)
 }
 
 /**
- * blk_execute_rq_nowait - insert a request into queue for execution
- * @q:		queue to insert the request in
+ * blk_execute_rq_nowait - insert a request to I/O scheduler for execution
  * @bd_disk:	matching gendisk
  * @rq:		request to insert
  * @at_head:    insert request at head or tail of queue
@@ -45,9 +44,8 @@ static void blk_end_sync_rq(struct request *rq, blk_status_t error)
  * Note:
  *    This function will invoke @done directly if the queue is dead.
  */
-void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
-			   struct request *rq, int at_head,
-			   rq_end_io_fn *done)
+void blk_execute_rq_nowait(struct gendisk *bd_disk, struct request *rq,
+			   int at_head, rq_end_io_fn *done)
 {
 	WARN_ON(irqs_disabled());
 	WARN_ON(!blk_rq_is_passthrough(rq));
@@ -83,7 +81,7 @@ void blk_execute_rq(struct request_queue *q, struct gendisk *bd_disk,
 	unsigned long hang_check;
 
 	rq->end_io_data = &wait;
-	blk_execute_rq_nowait(q, bd_disk, rq, at_head, blk_end_sync_rq);
+	blk_execute_rq_nowait(bd_disk, rq, at_head, blk_end_sync_rq);
 
 	/* Prevent hang_check timer from firing at us during very long I/O */
 	hang_check = sysctl_hung_task_timeout_secs;
diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c
index 4478eb7efee0..2cdf2771f8e8 100644
--- a/drivers/block/sx8.c
+++ b/drivers/block/sx8.c
@@ -539,7 +539,7 @@ static int carm_array_info (struct carm_host *host, unsigned int array_idx)
 	spin_unlock_irq(&host->lock);
 
 	DPRINTK("blk_execute_rq_nowait, tag == %u\n", rq->tag);
-	blk_execute_rq_nowait(host->oob_q, NULL, rq, true, NULL);
+	blk_execute_rq_nowait(NULL, rq, true, NULL);
 
 	return 0;
 
@@ -578,7 +578,7 @@ static int carm_send_special (struct carm_host *host, carm_sspc_t func)
 	crq->msg_bucket = (u32) rc;
 
 	DPRINTK("blk_execute_rq_nowait, tag == %u\n", rq->tag);
-	blk_execute_rq_nowait(host->oob_q, NULL, rq, true, NULL);
+	blk_execute_rq_nowait(NULL, rq, true, NULL);
 
 	return 0;
 }
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index f320273fc672..63c469edb1bc 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -925,7 +925,7 @@ static void nvme_execute_rq_polled(struct request_queue *q,
 
 	rq->cmd_flags |= REQ_HIPRI;
 	rq->end_io_data = &wait;
-	blk_execute_rq_nowait(q, bd_disk, rq, at_head, nvme_end_sync_rq);
+	blk_execute_rq_nowait(bd_disk, rq, at_head, nvme_end_sync_rq);
 
 	while (!completion_done(&wait)) {
 		blk_poll(q, request_to_qc_t(rq->mq_hctx, rq), true);
@@ -1202,7 +1202,7 @@ static int nvme_keep_alive(struct nvme_ctrl *ctrl)
 	rq->timeout = ctrl->kato * HZ;
 	rq->end_io_data = ctrl;
 
-	blk_execute_rq_nowait(rq->q, NULL, rq, 0, nvme_keep_alive_end_io);
+	blk_execute_rq_nowait(NULL, rq, 0, nvme_keep_alive_end_io);
 
 	return 0;
 }
diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index 470cef3abec3..439f2b52e985 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -695,7 +695,7 @@ static int nvme_nvm_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd,
 
 	rq->end_io_data = rqd;
 
-	blk_execute_rq_nowait(q, NULL, rq, 0, nvme_nvm_end_io);
+	blk_execute_rq_nowait(NULL, rq, 0, nvme_nvm_end_io);
 
 	return 0;
 
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 50d9a20568a2..6aa11067c8d0 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -1327,7 +1327,7 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved)
 	}
 
 	abort_req->end_io_data = NULL;
-	blk_execute_rq_nowait(abort_req->q, NULL, abort_req, 0, abort_endio);
+	blk_execute_rq_nowait(NULL, abort_req, 0, abort_endio);
 
 	/*
 	 * The aborted req will be completed on receiving the abort req.
@@ -2238,7 +2238,7 @@ static int nvme_delete_queue(struct nvme_queue *nvmeq, u8 opcode)
 	req->end_io_data = nvmeq;
 
 	init_completion(&nvmeq->delete_done);
-	blk_execute_rq_nowait(q, NULL, req, false,
+	blk_execute_rq_nowait(NULL, req, false,
 			opcode == nvme_admin_delete_cq ?
 				nvme_del_cq_end : nvme_del_queue_end);
 	return 0;
diff --git a/drivers/nvme/target/passthru.c b/drivers/nvme/target/passthru.c
index b9776fc8f08f..cbc88acdd233 100644
--- a/drivers/nvme/target/passthru.c
+++ b/drivers/nvme/target/passthru.c
@@ -275,7 +275,7 @@ static void nvmet_passthru_execute_cmd(struct nvmet_req *req)
 		schedule_work(&req->p.work);
 	} else {
 		rq->end_io_data = req;
-		blk_execute_rq_nowait(rq->q, ns ? ns->disk : NULL, rq, 0,
+		blk_execute_rq_nowait(ns ? ns->disk : NULL, rq, 0,
 				      nvmet_passthru_req_done);
 	}
 
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index f11f51e2465f..c00f06e9ecb0 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -2007,7 +2007,7 @@ static void scsi_eh_lock_door(struct scsi_device *sdev)
 	req->timeout = 10 * HZ;
 	rq->retries = 5;
 
-	blk_execute_rq_nowait(req->q, NULL, req, 1, eh_lock_door_done);
+	blk_execute_rq_nowait(NULL, req, 1, eh_lock_door_done);
 }
 
 /**
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index bfa8d77322d7..4383d93110f8 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -829,8 +829,7 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp,
 
 	srp->rq->timeout = timeout;
 	kref_get(&sfp->f_ref); /* sg_rq_end_io() does kref_put(). */
-	blk_execute_rq_nowait(sdp->device->request_queue, sdp->disk,
-			      srp->rq, at_head, sg_rq_end_io);
+	blk_execute_rq_nowait(sdp->disk, srp->rq, at_head, sg_rq_end_io);
 	return 0;
 }
 
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 43f7624508a9..841ad2fc369a 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -585,7 +585,7 @@ static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd,
 	rq->retries = retries;
 	req->end_io_data = SRpnt;
 
-	blk_execute_rq_nowait(req->q, NULL, req, 1, st_scsi_execute_end);
+	blk_execute_rq_nowait(NULL, req, 1, st_scsi_execute_end);
 	return 0;
 }
 
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c
index 7994f27e4527..33770e5808ce 100644
--- a/drivers/target/target_core_pscsi.c
+++ b/drivers/target/target_core_pscsi.c
@@ -1000,8 +1000,7 @@ pscsi_execute_cmd(struct se_cmd *cmd)
 		req->timeout = PS_TIMEOUT_OTHER;
 	scsi_req(req)->retries = PS_RETRY;
 
-	blk_execute_rq_nowait(pdv->pdv_sd->request_queue, NULL, req,
-			(cmd->sam_task_attr == TCM_HEAD_TAG),
+	blk_execute_rq_nowait(NULL, req, (cmd->sam_task_attr == TCM_HEAD_TAG),
 			pscsi_req_done);
 
 	return 0;
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 070de09425ad..bf0ddef8aa10 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -942,7 +942,7 @@ extern int blk_rq_map_user_iov(struct request_queue *, struct request *,
 			       gfp_t);
 extern void blk_execute_rq(struct request_queue *, struct gendisk *,
 			  struct request *, int);
-extern void blk_execute_rq_nowait(struct request_queue *, struct gendisk *,
+extern void blk_execute_rq_nowait(struct gendisk *,
 				  struct request *, int, rq_end_io_fn *);
 
 /* Helper to convert REQ_OP_XXX to its string format XXX */
-- 
2.17.1



From guoqing.jiang at cloud.ionos.com  Thu Jan 21 09:29:05 2021
From: guoqing.jiang at cloud.ionos.com (Guoqing Jiang)
Date: Thu, 21 Jan 2021 15:29:05 +0100
Subject: [PATCH 2/2] block: remove unnecessary argument from blk_execute_rq
In-Reply-To: <20210121142905.13089-1-guoqing.jiang@cloud.ionos.com>
References: <20210121142905.13089-1-guoqing.jiang@cloud.ionos.com>
Message-ID: <20210121142905.13089-3-guoqing.jiang@cloud.ionos.com>

We can remove 'q' from blk_execute_rq as well after the previous change
in blk_execute_rq_nowait.

Cc: linux-scsi at vger.kernel.org
Cc: virtualization at lists.linux-foundation.org
Cc: linux-ide at vger.kernel.org
Cc: linux-mmc at vger.kernel.org
Cc: linux-nvme at lists.infradead.org
Cc: linux-nfs at vger.kernel.org
Signed-off-by: Guoqing Jiang <guoqing.jiang at cloud.ionos.com>
---
 block/blk-exec.c                  |  3 +--
 block/bsg.c                       |  2 +-
 block/scsi_ioctl.c                |  6 +++---
 drivers/block/mtip32xx/mtip32xx.c |  2 +-
 drivers/block/paride/pd.c         |  2 +-
 drivers/block/pktcdvd.c           |  2 +-
 drivers/block/virtio_blk.c        |  2 +-
 drivers/cdrom/cdrom.c             |  2 +-
 drivers/ide/ide-atapi.c           |  2 +-
 drivers/ide/ide-cd.c              |  2 +-
 drivers/ide/ide-cd_ioctl.c        |  2 +-
 drivers/ide/ide-devsets.c         |  2 +-
 drivers/ide/ide-disk.c            |  2 +-
 drivers/ide/ide-ioctls.c          |  4 ++--
 drivers/ide/ide-park.c            |  2 +-
 drivers/ide/ide-pm.c              |  4 ++--
 drivers/ide/ide-tape.c            |  2 +-
 drivers/ide/ide-taskfile.c        |  2 +-
 drivers/mmc/core/block.c          | 10 +++++-----
 drivers/nvme/host/core.c          |  4 ++--
 drivers/nvme/host/lightnvm.c      |  2 +-
 drivers/scsi/scsi_lib.c           |  2 +-
 fs/nfsd/blocklayout.c             |  2 +-
 include/linux/blkdev.h            |  3 +--
 24 files changed, 33 insertions(+), 35 deletions(-)

diff --git a/block/blk-exec.c b/block/blk-exec.c
index 2e37e85456fb..0ab873f10133 100644
--- a/block/blk-exec.c
+++ b/block/blk-exec.c
@@ -74,8 +74,7 @@ EXPORT_SYMBOL_GPL(blk_execute_rq_nowait);
  *    Insert a fully prepared request at the back of the I/O scheduler queue
  *    for execution and wait for completion.
  */
-void blk_execute_rq(struct request_queue *q, struct gendisk *bd_disk,
-		   struct request *rq, int at_head)
+void blk_execute_rq(struct gendisk *bd_disk, struct request *rq, int at_head)
 {
 	DECLARE_COMPLETION_ONSTACK(wait);
 	unsigned long hang_check;
diff --git a/block/bsg.c b/block/bsg.c
index d7bae94b64d9..26e74a1ad9e2 100644
--- a/block/bsg.c
+++ b/block/bsg.c
@@ -181,7 +181,7 @@ static int bsg_sg_io(struct request_queue *q, fmode_t mode, void __user *uarg)
 
 	bio = rq->bio;
 
-	blk_execute_rq(q, NULL, rq, !(hdr.flags & BSG_FLAG_Q_AT_TAIL));
+	blk_execute_rq(NULL, rq, !(hdr.flags & BSG_FLAG_Q_AT_TAIL));
 	ret = rq->q->bsg_dev.ops->complete_rq(rq, &hdr);
 	blk_rq_unmap_user(bio);
 
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index c9f009cc0446..6599bac0a78c 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -357,7 +357,7 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
 	 * (if he doesn't check that is his problem).
 	 * N.B. a non-zero SCSI status is _not_ necessarily an error.
 	 */
-	blk_execute_rq(q, bd_disk, rq, at_head);
+	blk_execute_rq(bd_disk, rq, at_head);
 
 	hdr->duration = jiffies_to_msecs(jiffies - start_time);
 
@@ -493,7 +493,7 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode,
 		goto error;
 	}
 
-	blk_execute_rq(q, disk, rq, 0);
+	blk_execute_rq(disk, rq, 0);
 
 	err = req->result & 0xff;	/* only 8 bit SCSI status */
 	if (err) {
@@ -532,7 +532,7 @@ static int __blk_send_generic(struct request_queue *q, struct gendisk *bd_disk,
 	scsi_req(rq)->cmd[0] = cmd;
 	scsi_req(rq)->cmd[4] = data;
 	scsi_req(rq)->cmd_len = 6;
-	blk_execute_rq(q, bd_disk, rq, 0);
+	blk_execute_rq(bd_disk, rq, 0);
 	err = scsi_req(rq)->result ? -EIO : 0;
 	blk_put_request(rq);
 
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c
index 53ac59d19ae5..3fd99836bb1c 100644
--- a/drivers/block/mtip32xx/mtip32xx.c
+++ b/drivers/block/mtip32xx/mtip32xx.c
@@ -1015,7 +1015,7 @@ static int mtip_exec_internal_command(struct mtip_port *port,
 	rq->timeout = timeout;
 
 	/* insert request and run queue */
-	blk_execute_rq(rq->q, NULL, rq, true);
+	blk_execute_rq(NULL, rq, true);
 
 	if (int_cmd->status) {
 		dev_err(&dd->pdev->dev, "Internal command [%02X] failed %d\n",
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index a7af4f27b7c3..897acda20ac8 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -781,7 +781,7 @@ static int pd_special_command(struct pd_unit *disk,
 	req = blk_mq_rq_to_pdu(rq);
 
 	req->func = func;
-	blk_execute_rq(disk->gd->queue, disk->gd, rq, 0);
+	blk_execute_rq(disk->gd, rq, 0);
 	blk_put_request(rq);
 	return 0;
 }
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index b8bb8ec7538d..7ce4533a4831 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -722,7 +722,7 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *
 	if (cgc->quiet)
 		rq->rq_flags |= RQF_QUIET;
 
-	blk_execute_rq(rq->q, pd->bdev->bd_disk, rq, 0);
+	blk_execute_rq(pd->bdev->bd_disk, rq, 0);
 	if (scsi_req(rq)->result)
 		ret = -EIO;
 out:
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 145606dc52db..b0285db7cf4f 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -320,7 +320,7 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str)
 	if (err)
 		goto out;
 
-	blk_execute_rq(vblk->disk->queue, vblk->disk, req, false);
+	blk_execute_rq(vblk->disk, req, false);
 	err = blk_status_to_errno(virtblk_result(blk_mq_rq_to_pdu(req)));
 out:
 	blk_put_request(req);
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index 8f0e52a71493..90ad34c6ef8e 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -2214,7 +2214,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
 		rq->timeout = 60 * HZ;
 		bio = rq->bio;
 
-		blk_execute_rq(q, cdi->disk, rq, 0);
+		blk_execute_rq(cdi->disk, rq, 0);
 		if (scsi_req(rq)->result) {
 			struct scsi_sense_hdr sshdr;
 
diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c
index 2162bc80f09e..19aaa8f8aacf 100644
--- a/drivers/ide/ide-atapi.c
+++ b/drivers/ide/ide-atapi.c
@@ -107,7 +107,7 @@ int ide_queue_pc_tail(ide_drive_t *drive, struct gendisk *disk,
 	memcpy(scsi_req(rq)->cmd, pc->c, 12);
 	if (drive->media == ide_tape)
 		scsi_req(rq)->cmd[13] = REQ_IDETAPE_PC1;
-	blk_execute_rq(drive->queue, disk, rq, 0);
+	blk_execute_rq(disk, rq, 0);
 	error = scsi_req(rq)->result ? -EIO : 0;
 put_req:
 	blk_put_request(rq);
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 25d2d88e82ad..cffbcc27a34c 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -467,7 +467,7 @@ int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd,
 			}
 		}
 
-		blk_execute_rq(drive->queue, info->disk, rq, 0);
+		blk_execute_rq(info->disk, rq, 0);
 		error = scsi_req(rq)->result ? -EIO : 0;
 
 		if (buffer)
diff --git a/drivers/ide/ide-cd_ioctl.c b/drivers/ide/ide-cd_ioctl.c
index 46f2df288c6a..011eab9c69b7 100644
--- a/drivers/ide/ide-cd_ioctl.c
+++ b/drivers/ide/ide-cd_ioctl.c
@@ -299,7 +299,7 @@ int ide_cdrom_reset(struct cdrom_device_info *cdi)
 	rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0);
 	ide_req(rq)->type = ATA_PRIV_MISC;
 	rq->rq_flags = RQF_QUIET;
-	blk_execute_rq(drive->queue, cd->disk, rq, 0);
+	blk_execute_rq(cd->disk, rq, 0);
 	ret = scsi_req(rq)->result ? -EIO : 0;
 	blk_put_request(rq);
 	/*
diff --git a/drivers/ide/ide-devsets.c b/drivers/ide/ide-devsets.c
index f2f93ed40356..ca1d4b3d3878 100644
--- a/drivers/ide/ide-devsets.c
+++ b/drivers/ide/ide-devsets.c
@@ -173,7 +173,7 @@ int ide_devset_execute(ide_drive_t *drive, const struct ide_devset *setting,
 	*(int *)&scsi_req(rq)->cmd[1] = arg;
 	ide_req(rq)->special = setting->set;
 
-	blk_execute_rq(q, NULL, rq, 0);
+	blk_execute_rq(NULL, rq, 0);
 	ret = scsi_req(rq)->result;
 	blk_put_request(rq);
 
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index 34b9441084f8..8413731c6259 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -482,7 +482,7 @@ static int set_multcount(ide_drive_t *drive, int arg)
 
 	drive->mult_req = arg;
 	drive->special_flags |= IDE_SFLAG_SET_MULTMODE;
-	blk_execute_rq(drive->queue, NULL, rq, 0);
+	blk_execute_rq(NULL, rq, 0);
 	blk_put_request(rq);
 
 	return (drive->mult_count == arg) ? 0 : -EIO;
diff --git a/drivers/ide/ide-ioctls.c b/drivers/ide/ide-ioctls.c
index 58994da10c06..43fbc37d85c3 100644
--- a/drivers/ide/ide-ioctls.c
+++ b/drivers/ide/ide-ioctls.c
@@ -137,7 +137,7 @@ static int ide_cmd_ioctl(ide_drive_t *drive, void __user *argp)
 
 		rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0);
 		ide_req(rq)->type = ATA_PRIV_TASKFILE;
-		blk_execute_rq(drive->queue, NULL, rq, 0);
+		blk_execute_rq(NULL, rq, 0);
 		err = scsi_req(rq)->result ? -EIO : 0;
 		blk_put_request(rq);
 
@@ -235,7 +235,7 @@ static int generic_drive_reset(ide_drive_t *drive)
 	ide_req(rq)->type = ATA_PRIV_MISC;
 	scsi_req(rq)->cmd_len = 1;
 	scsi_req(rq)->cmd[0] = REQ_DRIVE_RESET;
-	blk_execute_rq(drive->queue, NULL, rq, 1);
+	blk_execute_rq(NULL, rq, 1);
 	ret = scsi_req(rq)->result;
 	blk_put_request(rq);
 	return ret;
diff --git a/drivers/ide/ide-park.c b/drivers/ide/ide-park.c
index 8af7af6001eb..a80a0f28f7b9 100644
--- a/drivers/ide/ide-park.c
+++ b/drivers/ide/ide-park.c
@@ -37,7 +37,7 @@ static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout)
 	scsi_req(rq)->cmd_len = 1;
 	ide_req(rq)->type = ATA_PRIV_MISC;
 	ide_req(rq)->special = &timeout;
-	blk_execute_rq(q, NULL, rq, 1);
+	blk_execute_rq(NULL, rq, 1);
 	rc = scsi_req(rq)->result ? -EIO : 0;
 	blk_put_request(rq);
 	if (rc)
diff --git a/drivers/ide/ide-pm.c b/drivers/ide/ide-pm.c
index 192e6c65d34e..fc3cb37fec14 100644
--- a/drivers/ide/ide-pm.c
+++ b/drivers/ide/ide-pm.c
@@ -27,7 +27,7 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg)
 		mesg.event = PM_EVENT_FREEZE;
 	rqpm.pm_state = mesg.event;
 
-	blk_execute_rq(drive->queue, NULL, rq, 0);
+	blk_execute_rq(NULL, rq, 0);
 	ret = scsi_req(rq)->result ? -EIO : 0;
 	blk_put_request(rq);
 
@@ -50,7 +50,7 @@ static int ide_pm_execute_rq(struct request *rq)
 		blk_mq_end_request(rq, BLK_STS_OK);
 		return -ENXIO;
 	}
-	blk_execute_rq(q, NULL, rq, true);
+	blk_execute_rq(NULL, rq, true);
 
 	return scsi_req(rq)->result ? -EIO : 0;
 }
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index 88b96437b22e..fa05e7e7d609 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -868,7 +868,7 @@ static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int size)
 			goto out_put;
 	}
 
-	blk_execute_rq(drive->queue, tape->disk, rq, 0);
+	blk_execute_rq(tape->disk, rq, 0);
 
 	/* calculate the number of transferred bytes and update buffer state */
 	size -= scsi_req(rq)->resid_len;
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index d016cbe68cba..6665fc4724b9 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -443,7 +443,7 @@ int ide_raw_taskfile(ide_drive_t *drive, struct ide_cmd *cmd, u8 *buf,
 	ide_req(rq)->special = cmd;
 	cmd->rq = rq;
 
-	blk_execute_rq(drive->queue, NULL, rq, 0);
+	blk_execute_rq(NULL, rq, 0);
 	error = scsi_req(rq)->result ? -EIO : 0;
 put_req:
 	blk_put_request(rq);
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index 42e27a298218..a1d6b68320ae 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -253,7 +253,7 @@ static ssize_t power_ro_lock_store(struct device *dev,
 		goto out_put;
 	}
 	req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_BOOT_WP;
-	blk_execute_rq(mq->queue, NULL, req, 0);
+	blk_execute_rq(NULL, req, 0);
 	ret = req_to_mmc_queue_req(req)->drv_op_result;
 	blk_put_request(req);
 
@@ -629,7 +629,7 @@ static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md,
 		rpmb ? MMC_DRV_OP_IOCTL_RPMB : MMC_DRV_OP_IOCTL;
 	req_to_mmc_queue_req(req)->drv_op_data = idatas;
 	req_to_mmc_queue_req(req)->ioc_count = 1;
-	blk_execute_rq(mq->queue, NULL, req, 0);
+	blk_execute_rq(NULL, req, 0);
 	ioc_err = req_to_mmc_queue_req(req)->drv_op_result;
 	err = mmc_blk_ioctl_copy_to_user(ic_ptr, idata);
 	blk_put_request(req);
@@ -698,7 +698,7 @@ static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md,
 		rpmb ? MMC_DRV_OP_IOCTL_RPMB : MMC_DRV_OP_IOCTL;
 	req_to_mmc_queue_req(req)->drv_op_data = idata;
 	req_to_mmc_queue_req(req)->ioc_count = num_of_cmds;
-	blk_execute_rq(mq->queue, NULL, req, 0);
+	blk_execute_rq(NULL, req, 0);
 	ioc_err = req_to_mmc_queue_req(req)->drv_op_result;
 
 	/* copy to user if data and response */
@@ -2722,7 +2722,7 @@ static int mmc_dbg_card_status_get(void *data, u64 *val)
 	if (IS_ERR(req))
 		return PTR_ERR(req);
 	req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_GET_CARD_STATUS;
-	blk_execute_rq(mq->queue, NULL, req, 0);
+	blk_execute_rq(NULL, req, 0);
 	ret = req_to_mmc_queue_req(req)->drv_op_result;
 	if (ret >= 0) {
 		*val = ret;
@@ -2761,7 +2761,7 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp)
 	}
 	req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_GET_EXT_CSD;
 	req_to_mmc_queue_req(req)->drv_op_data = &ext_csd;
-	blk_execute_rq(mq->queue, NULL, req, 0);
+	blk_execute_rq(NULL, req, 0);
 	err = req_to_mmc_queue_req(req)->drv_op_result;
 	blk_put_request(req);
 	if (err) {
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 63c469edb1bc..d3d6e950dda2 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -964,7 +964,7 @@ int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
 	if (poll)
 		nvme_execute_rq_polled(req->q, NULL, req, at_head);
 	else
-		blk_execute_rq(req->q, NULL, req, at_head);
+		blk_execute_rq(NULL, req, at_head);
 	if (result)
 		*result = nvme_req(req)->result;
 	if (nvme_req(req)->flags & NVME_REQ_CANCELLED)
@@ -1101,7 +1101,7 @@ void nvme_execute_passthru_rq(struct request *rq)
 	u32 effects;
 
 	effects = nvme_passthru_start(ctrl, ns, cmd->common.opcode);
-	blk_execute_rq(rq->q, disk, rq, 0);
+	blk_execute_rq(disk, rq, 0);
 	nvme_passthru_end(ctrl, effects);
 }
 EXPORT_SYMBOL_NS_GPL(nvme_execute_passthru_rq, NVME_TARGET_PASSTHRU);
diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index 439f2b52e985..e0443755884b 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -820,7 +820,7 @@ static int nvme_nvm_submit_user_cmd(struct request_queue *q,
 		bio->bi_disk = disk;
 	}
 
-	blk_execute_rq(q, NULL, rq, 0);
+	blk_execute_rq(NULL, rq, 0);
 
 	if (nvme_req(rq)->flags & NVME_REQ_CANCELLED)
 		ret = -EINTR;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 4848ae3c7b56..475e40c9493f 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -268,7 +268,7 @@ int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
 	/*
 	 * head injection *required* here otherwise quiesce won't work
 	 */
-	blk_execute_rq(req->q, NULL, req, 1);
+	blk_execute_rq(NULL, req, 1);
 
 	/*
 	 * Some devices (USB mass-storage in particular) may transfer
diff --git a/fs/nfsd/blocklayout.c b/fs/nfsd/blocklayout.c
index a07c39c94bbd..1058659a8d31 100644
--- a/fs/nfsd/blocklayout.c
+++ b/fs/nfsd/blocklayout.c
@@ -254,7 +254,7 @@ static int nfsd4_scsi_identify_device(struct block_device *bdev,
 	req->cmd[4] = bufflen & 0xff;
 	req->cmd_len = COMMAND_SIZE(INQUIRY);
 
-	blk_execute_rq(rq->q, NULL, rq, 1);
+	blk_execute_rq(NULL, rq, 1);
 	if (req->result) {
 		pr_err("pNFS: INQUIRY 0x83 failed with: %x\n",
 			req->result);
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index bf0ddef8aa10..09caa1de28b0 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -940,8 +940,7 @@ extern int blk_rq_map_kern(struct request_queue *, struct request *, void *, uns
 extern int blk_rq_map_user_iov(struct request_queue *, struct request *,
 			       struct rq_map_data *, const struct iov_iter *,
 			       gfp_t);
-extern void blk_execute_rq(struct request_queue *, struct gendisk *,
-			  struct request *, int);
+extern void blk_execute_rq(struct gendisk *, struct request *, int);
 extern void blk_execute_rq_nowait(struct gendisk *,
 				  struct request *, int, rq_end_io_fn *);
 
-- 
2.17.1



From hch at infradead.org  Thu Jan 21 12:02:57 2021
From: hch at infradead.org (Christoph Hellwig)
Date: Thu, 21 Jan 2021 17:02:57 +0000
Subject: [PATCH 1/2] block: remove unnecessary argument from
 blk_execute_rq_nowait
In-Reply-To: <20210121142905.13089-2-guoqing.jiang@cloud.ionos.com>
References: <20210121142905.13089-1-guoqing.jiang@cloud.ionos.com>
 <20210121142905.13089-2-guoqing.jiang@cloud.ionos.com>
Message-ID: <20210121170257.GA4120717@infradead.org>

On Thu, Jan 21, 2021 at 03:29:04PM +0100, Guoqing Jiang wrote:
> The 'q' is not used since commit a1ce35fa4985 ("block: remove dead
> elevator code"), also update the comment of the function.

And more importantly it never really was needed to start with given
that we can triviall derive it from struct request.

> -extern void blk_execute_rq_nowait(struct request_queue *, struct gendisk *,
> +extern void blk_execute_rq_nowait(struct gendisk *,
>  				  struct request *, int, rq_end_io_fn *);


From hch at infradead.org  Thu Jan 21 12:04:25 2021
From: hch at infradead.org (Christoph Hellwig)
Date: Thu, 21 Jan 2021 17:04:25 +0000
Subject: [PATCH 2/2] block: remove unnecessary argument from blk_execute_rq
In-Reply-To: <20210121142905.13089-3-guoqing.jiang@cloud.ionos.com>
References: <20210121142905.13089-1-guoqing.jiang@cloud.ionos.com>
 <20210121142905.13089-3-guoqing.jiang@cloud.ionos.com>
Message-ID: <20210121170425.GB4120717@infradead.org>

On Thu, Jan 21, 2021 at 03:29:05PM +0100, Guoqing Jiang wrote:
> We can remove 'q' from blk_execute_rq as well after the previous change
> in blk_execute_rq_nowait.

Same trivial nits as for the other one.

Otherwise this looks good to me.


From kbusch at kernel.org  Thu Jan 21 12:07:35 2021
From: kbusch at kernel.org (Keith Busch)
Date: Fri, 22 Jan 2021 02:07:35 +0900
Subject: kernel oops after nvme_set_queue_count()
In-Reply-To: <d5f00c36-2981-0a0c-7a6d-b4ab2c8d139e@suse.de>
References: <d5f00c36-2981-0a0c-7a6d-b4ab2c8d139e@suse.de>
Message-ID: <20210121170735.GA32223@redsun51.ssa.fujisawa.hgst.com>

On Thu, Jan 21, 2021 at 09:25:39AM +0100, Hannes Reinecke wrote:
> Hi all,
> 
> a customer of ours ran into this oops:
> 
> [44157.918962] nvme nvme5: I/O 22 QID 0 timeout
> [44163.347467] nvme nvme5: Could not set queue count (880)
> [44163.347551] nvme nvme5: Successfully reconnected (6 attempts)
> [44168.414977] BUG: unable to handle kernel paging request at
> ffff888e261e7808
> [44168.414988] IP: 0xffff888e261e7808
> [44168.414994] PGD 98c2ae067 P4D 98c2ae067 PUD f57937063 PMD
> 8000000f660001e3
> 
> It's related to this code snippet in drivers/nvme/host/core.c
> 
> 	/*
> 	 * Degraded controllers might return an error when setting the queue
> 	 * count.  We still want to be able to bring them online and offer
> 	 * access to the admin queue, as that might be only way to fix them up.
> 	 */
> 	if (status > 0) {
> 		dev_err(ctrl->device, "Could not set queue count (%d)\n", status);
> 		*count = 0;
> 
> 
> causing nvme_set_queue_count() _not_ to return an error, but rather let the
> reconnect complete.
> Of course, as this failure is due to a timeout (cf the status code; 880
> is NVME_SC_HOST_PATH_ERROR), the admin queue has been torn down by the
> transport, causing this crash.

This doesn't sound right. No response from a controller timeout is
supposed to get the -EINTR return, which exits earlier with a returned
error above what you're showing.


From Chaitanya.Kulkarni at wdc.com  Thu Jan 21 15:03:20 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Thu, 21 Jan 2021 20:03:20 +0000
Subject: [PATCH] nvme: do not ignore nvme status in nvme_set_queue_count()
References: <20210121095021.22807-1-hare@suse.de>
Message-ID: <BYAPR04MB4965DAA1B3A63EFBBA23BE1986A10@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/21/21 1:54 AM, Hannes Reinecke wrote:
> If the call to nvme_set_queue_count() fails with a status we should
> not ignore it but rather pass it on to the caller.
> It's then up to the transport to decide whether to ignore it
> (like PCI does) or to reset the connection (as would be appropriate
> for fabrics).
>
> Signed-off-by: Hannes Reinecke <hare at suse.de>
> ---
>  drivers/nvme/host/core.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
> index ce1b61519441..ddf32f5b4534 100644
> --- a/drivers/nvme/host/core.c
> +++ b/drivers/nvme/host/core.c
> @@ -1486,7 +1486,7 @@ int nvme_set_queue_count(struct nvme_ctrl *ctrl, int *count)
>  		*count = min(*count, nr_io_queues);
>  	}
>  
> -	return 0;
> +	return status;
>  }
>  EXPORT_SYMBOL_GPL(nvme_set_queue_count);
>  
Looks good.

Reviewed-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>


From kbusch at kernel.org  Thu Jan 21 15:14:59 2021
From: kbusch at kernel.org (Keith Busch)
Date: Thu, 21 Jan 2021 12:14:59 -0800
Subject: [PATCH] nvme: do not ignore nvme status in nvme_set_queue_count()
In-Reply-To: <20210121095021.22807-1-hare@suse.de>
References: <20210121095021.22807-1-hare@suse.de>
Message-ID: <20210121201459.GA1727271@dhcp-10-100-145-180.wdc.com>

On Thu, Jan 21, 2021 at 10:50:21AM +0100, Hannes Reinecke wrote:
> If the call to nvme_set_queue_count() fails with a status we should
> not ignore it but rather pass it on to the caller.
> It's then up to the transport to decide whether to ignore it
> (like PCI does) or to reset the connection (as would be appropriate
> for fabrics).

Instead of checking the error, wouldn't checking the number of created
queues be sufficient? What handling difference do you expect to occur
between getting a success with 0 queues, vs getting an error?


From lengchao at huawei.com  Thu Jan 21 20:45:40 2021
From: lengchao at huawei.com (Chao Leng)
Date: Fri, 22 Jan 2021 09:45:40 +0800
Subject: [PATCH v2 2/6] nvme-core: introduce complete failed request
In-Reply-To: <93e16361-6973-5245-b040-692ef2ec4d79@suse.de>
References: <20210107033149.15701-1-lengchao@huawei.com>
 <20210107033149.15701-3-lengchao@huawei.com>
 <93e16361-6973-5245-b040-692ef2ec4d79@suse.de>
Message-ID: <65d190fb-4a9d-1776-01aa-786acc306a1c@huawei.com>



On 2021/1/21 16:14, Hannes Reinecke wrote:
> On 1/7/21 4:31 AM, Chao Leng wrote:
>> When a request is queued failed, if the fail status is not
>> BLK_STS_RESOURCE, BLK_STS_DEV_RESOURCE, BLK_STS_ZONE_RESOURCE,
>> the request is need to complete with nvme_complete_rq in queue_rq.
>> So introduce nvme_try_complete_failed_req.
>> The request is needed to complete with NVME_SC_HOST_PATH_ERROR in
>> nvmf_fail_nonready_command and queue_rq.
>> So introduce nvme_complete_failed_req.
>> For details, see the subsequent patches.
>>
>> Signed-off-by: Chao Leng <lengchao at huawei.com>
>> ---
>> ? drivers/nvme/host/nvme.h | 21 +++++++++++++++++++++
>> ? 1 file changed, 21 insertions(+)
>>
>> diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
>> index bfcedfa4b057..fc4eefdfbb34 100644
>> --- a/drivers/nvme/host/nvme.h
>> +++ b/drivers/nvme/host/nvme.h
>> @@ -649,6 +649,27 @@ void nvme_put_ns_from_disk(struct nvme_ns_head *head, int idx);
>> ? extern const struct attribute_group *nvme_ns_id_attr_groups[];
>> ? extern const struct block_device_operations nvme_ns_head_ops;
>> +static inline void nvme_complete_failed_req(struct request *req)
>> +{
>> +??? nvme_req(req)->status = NVME_SC_HOST_PATH_ERROR;
>> +??? blk_mq_set_request_complete(req);
>> +??? nvme_complete_rq(req);
>> +}
>> +
>> +static inline blk_status_t nvme_try_complete_failed_req(struct request *req,
>> +??????????????????????????? blk_status_t ret)
>> +{
>> +??? switch (ret) {
>> +??? case BLK_STS_RESOURCE:
>> +??? case BLK_STS_DEV_RESOURCE:
>> +??? case BLK_STS_ZONE_RESOURCE:
>> +??????? return ret;
>> +??? default:
>> +??????? nvme_complete_failed_req(req);
>> +??????? return BLK_STS_OK;
>> +??? }
>> +}
>> +
>> ? #ifdef CONFIG_NVME_MULTIPATH
>> ? static inline bool nvme_ctrl_use_ana(struct nvme_ctrl *ctrl)
>> ? {
>>
> This is not correct.
> HOST_PATH_ERROR only should be set _iff_ it is a pathing issue, and the HBA/transport is equipped to determine that.
> Any other error have other causes, and we need to look at the individual error codes (and situations) to determine if this really is a pathing error.
Optimization has been made in patch v3.
> 
> Cheers,
> 
> Hannes


From lengchao at huawei.com  Thu Jan 21 20:46:15 2021
From: lengchao at huawei.com (Chao Leng)
Date: Fri, 22 Jan 2021 09:46:15 +0800
Subject: [PATCH v3 1/5] blk-mq: introduce blk_mq_set_request_complete
In-Reply-To: <20210121084059.GA25963@lst.de>
References: <20210121070330.19701-1-lengchao@huawei.com>
 <20210121070330.19701-2-lengchao@huawei.com> <20210121084059.GA25963@lst.de>
Message-ID: <e053944e-e8de-187e-78f2-21974fb97dbf@huawei.com>



On 2021/1/21 16:40, Christoph Hellwig wrote:
> On Thu, Jan 21, 2021 at 03:03:26PM +0800, Chao Leng wrote:
>> nvme drivers need to set the state of request to MQ_RQ_COMPLETE when
>> directly complete request in queue_rq.
>> So add blk_mq_set_request_complete.
> 
> So I'm not happy with this helper.  It should at least:
> 
>   a) be named and documented to only apply for the ->queue_rq fa?lure case
Although blk_mq_complete_request_remote can set the markup directly,
blk_mq_complete_request_remote can also use this helper. This helper do
not need special processing for ->queue_rq failure.
>   b) check that the request is in MQ_RQ_IDLE state
No, the request may also be in MQ_RQ_IN_FLIGHT state. Do not need to
care whether the original state is MQ_RQ_IDLE or MQ_RQ_IN_FLIGHT.
> .
> 


From lengchao at huawei.com  Thu Jan 21 20:46:41 2021
From: lengchao at huawei.com (Chao Leng)
Date: Fri, 22 Jan 2021 09:46:41 +0800
Subject: [PATCH v3 2/5] nvme-core: introduce complete failed request
In-Reply-To: <20210121084150.GB25963@lst.de>
References: <20210121070330.19701-1-lengchao@huawei.com>
 <20210121070330.19701-3-lengchao@huawei.com> <20210121084150.GB25963@lst.de>
Message-ID: <c833e26b-623e-47f5-2493-13cb83014905@huawei.com>



On 2021/1/21 16:41, Christoph Hellwig wrote:
>> +static inline void nvme_complete_failed_req(struct request *req)
> 
> I think the name is too generic, and the function also needs a little
> comment, especially as it forces a specific error code.
Ok, thank you for your suggestion. Use error status as a parameter may
be a better choice.
> 
>> +{
>> +	nvme_req(req)->status = NVME_SC_HOST_PATH_ERROR;
>> +	blk_mq_set_request_complete(req);
>> +	nvme_complete_rq(req);
>> +}
> 
> Also no need to mark this as an inline function.
Yes, export the function is ok.
> .
> 


From lengchao at huawei.com  Thu Jan 21 20:48:03 2021
From: lengchao at huawei.com (Chao Leng)
Date: Fri, 22 Jan 2021 09:48:03 +0800
Subject: [PATCH v3 3/5] nvme-fabrics: avoid double request completion for
 nvmf_fail_nonready_command
In-Reply-To: <fda1fdb8-8a9d-2e95-4d08-8d8ee1df450d@suse.de>
References: <20210121070330.19701-1-lengchao@huawei.com>
 <20210121070330.19701-4-lengchao@huawei.com>
 <fda1fdb8-8a9d-2e95-4d08-8d8ee1df450d@suse.de>
Message-ID: <a100b5dd-d38b-3158-d000-b84920a4e274@huawei.com>



On 2021/1/21 16:58, Hannes Reinecke wrote:
> On 1/21/21 8:03 AM, Chao Leng wrote:
>> When reconnect, the request may be completed with NVME_SC_HOST_PATH_ERROR
>> in nvmf_fail_nonready_command. The state of request will be changed to
>> MQ_RQ_IN_FLIGHT before call nvme_complete_rq. If free the request
>> asynchronously such as in nvme_submit_user_cmd, in extreme scenario
>> the request may be completed again in tear down process.
>> nvmf_fail_nonready_command do not need calling blk_mq_start_request
>> before complete the request. nvmf_fail_nonready_command should set
>> the state of request to MQ_RQ_COMPLETE before complete the request.
>>
> 
> So what you are saying is that there is a race condition between
> blk_mq_start_request()
> and
> nvme_complete_request()
Yes. The race is:
process1:error recovery->tear down->quiesce queue(wait dispatch done)
process2:dispatch->queue_rq->nvmf_fail_nonready_command->
     nvme_complete_rq(if the request is freed asynchronously, wake
	nvme_submit_user_cmd( for example) but have no chance to run).
process1:continue ->cancle suspend request, check the state is not
     MQ_RQ_IDLE and MQ_RQ_COMPLETE, complete(free) the request.
process3: nvme_submit_user_cmd now has chance to run, and the free the
     request again.
Test Injection Method: inject a msleep before call blk_mq_free_request
in nvme_submit_user_cmd.
> 
>> Signed-off-by: Chao Leng <lengchao at huawei.com>
>> ---
>> ? drivers/nvme/host/fabrics.c | 4 +---
>> ? 1 file changed, 1 insertion(+), 3 deletions(-)
>>
>> diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c
>> index 72ac00173500..874e4320e214 100644
>> --- a/drivers/nvme/host/fabrics.c
>> +++ b/drivers/nvme/host/fabrics.c
>> @@ -553,9 +553,7 @@ blk_status_t nvmf_fail_nonready_command(struct nvme_ctrl *ctrl,
>> ????????? !blk_noretry_request(rq) && !(rq->cmd_flags & REQ_NVME_MPATH))
>> ????????? return BLK_STS_RESOURCE;
>> -??? nvme_req(rq)->status = NVME_SC_HOST_PATH_ERROR;
>> -??? blk_mq_start_request(rq);
>> -??? nvme_complete_rq(rq);
>> +??? nvme_complete_failed_req(rq);
>> ????? return BLK_STS_OK;
>> ? }
>> ? EXPORT_SYMBOL_GPL(nvmf_fail_nonready_command);
>> I'd rather have 'nvme_complete_failed_req()' accept the status as 
> argument, like
> 
> nvme_complete_failed_request(rq, NVME_SC_HOST_PATH_ERROR)
> 
> that way it's obvious what is happening, and the status isn't hidden in the function.
Ok, good idea. Thank you for your suggestion.
> 
> Cheers,
> 
> Hannes


From lengchao at huawei.com  Thu Jan 21 20:50:16 2021
From: lengchao at huawei.com (Chao Leng)
Date: Fri, 22 Jan 2021 09:50:16 +0800
Subject: [PATCH v3 3/5] nvme-fabrics: avoid double request completion for
 nvmf_fail_nonready_command
In-Reply-To: <467a43b0-82cc-69b7-460a-413ddc8cf574@suse.de>
References: <20210121070330.19701-1-lengchao@huawei.com>
 <20210121070330.19701-4-lengchao@huawei.com>
 <fda1fdb8-8a9d-2e95-4d08-8d8ee1df450d@suse.de>
 <20210121090012.GA27342@lst.de>
 <467a43b0-82cc-69b7-460a-413ddc8cf574@suse.de>
Message-ID: <3bcd337b-3ab3-03ab-f9e6-a461cd8ee127@huawei.com>



On 2021/1/21 17:27, Hannes Reinecke wrote:
> On 1/21/21 10:00 AM, Christoph Hellwig wrote:
>> On Thu, Jan 21, 2021 at 09:58:37AM +0100, Hannes Reinecke wrote:
>>> On 1/21/21 8:03 AM, Chao Leng wrote:
>>>> When reconnect, the request may be completed with NVME_SC_HOST_PATH_ERROR
>>>> in nvmf_fail_nonready_command. The state of request will be changed to
>>>> MQ_RQ_IN_FLIGHT before call nvme_complete_rq. If free the request
>>>> asynchronously such as in nvme_submit_user_cmd, in extreme scenario
>>>> the request may be completed again in tear down process.
>>>> nvmf_fail_nonready_command do not need calling blk_mq_start_request
>>>> before complete the request. nvmf_fail_nonready_command should set
>>>> the state of request to MQ_RQ_COMPLETE before complete the request.
>>>>
>>>
>>> So what you are saying is that there is a race condition between
>>> blk_mq_start_request()
>>> and
>>> nvme_complete_request()
>>
>> Between those to a teardown that cancels all requests can come in.
>>
> Doesn't nvme_complete_request() insulate against a double completion?
nvme_complete_request can not insulate against double completion.
Setting the state of request to MQ_RQ_COMPLETE avoid double completion.
tear down(nvme_cancel_request) check the state of the request, if the
state is MQ_RQ_COMPLETE, it will skip completion.
> I seem to remember we've gone through great lengths ensuring that.
> 
> And if this is just about setting the correct error code on completion I'd really prefer to stick with the current code. Moving that into a helper is fine, but I'd rather not introduce our own code modifying request state.
> 
> If there really is a race condition this feels like a more generic problem; calling blk_mq_start_request() followed by blk_mq_end_request() is a quite common pattern, and from my impression the recommended way.
> So if there is an issue it would need to be addressed for all drivers, not just some nvme-specific way.
Currently, it is not safe for nvme. The probability is very low.
I am not sure whether similar occurs in other scenarios.
> Plus I'd like to have Jens' opinion here.
> 
> Cheers,
> 
> Hannes


From chapman6235 at comcast.net  Thu Jan 21 21:32:12 2021
From: chapman6235 at comcast.net (Bradley Chapman)
Date: Thu, 21 Jan 2021 21:32:12 -0500
Subject: Problem with SPCC 256GB NVMe 1.3 drive - refcount_t: underflow;
 use-after-free.
In-Reply-To: <20210121124459.GA156577@localhost.localdomain>
References: <f50bc59c-db11-bb44-55be-7b9db1119872@comcast.net>
 <BYAPR04MB49659C0F0F0E11D166B31E0586A40@BYAPR04MB4965.namprd04.prod.outlook.com>
 <a4c75497-d170-1e0f-8608-282231ff3a8e@comcast.net>
 <BYAPR04MB496542BEF594F0380F7D41CF86A20@BYAPR04MB4965.namprd04.prod.outlook.com>
 <df46d7ce-ce70-1f43-0efd-7153761bcff0@comcast.net>
 <20210121124459.GA156577@localhost.localdomain>
Message-ID: <96083ad4-e065-c071-bdc9-67517dc1e5a3@comcast.net>

Good evening,

On 1/21/21 7:45 AM, Niklas Cassel wrote:
> On Wed, Jan 20, 2021 at 09:33:08PM -0500, Bradley Chapman wrote:
>>>>> Also can you please also try the latest nvme tree branch nvme-5.11 ?
>>>>>
>>>> Where do I get that code from? Is it already in the 5.11-rc tree or do I
>>>> need to look somewhere else? I checked https://github.com/linux-nvme but
>>>> I did not see it there.
>>> Here is the link :-git://git.infradead.org/nvme.git
>>> Branch 5.12.
>>
>> I tried fetching the entire repo but it was huge and would have taken a long
>> time, so I tried to fetch a single branch instead and got this result:
>>
>> $ git clone --branch 5.12 --single-branch git://git.infradead.org/nvme.git
>> Cloning into 'nvme'...
>> warning: Could not find remote branch 5.12 to clone.
>> fatal: Remote branch 5.12 not found in upstream origin
>>
>> I haven't compiled any out-of-tree kernel code in a very long time - how
>> easy is it to add this code to a kernel tree and compile it into the kernel
>> once I've figured out how to get it?
> 
> Hello there,
> 
> You can see the available branches by replacing git:// with https:// i.e.:
> https://git.infradead.org/nvme.git
> 
> The branch is called nvme-5.12
> 
> It is not out-of-tree kernel code, it is a subsystem git tree,
> so you build the kernel like usual.
> 
> If you already have a kernel git tree somewhere,
> simply add an additional remote, and it should be quick:
> 
> $ git remote add nvme git://git.infradead.org/nvme.git && git fetch nvme

Thanks for the pointer. I've downloaded the code and will add it to a 
stable 5.10 tree and a 5.11-rc tree and see what happens.

> 
> 
> Kind regards,
> Niklas
> 

Brad


From Chaitanya.Kulkarni at wdc.com  Thu Jan 21 21:54:16 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Fri, 22 Jan 2021 02:54:16 +0000
Subject: Problem with SPCC 256GB NVMe 1.3 drive - refcount_t: underflow;
 use-after-free.
References: <f50bc59c-db11-bb44-55be-7b9db1119872@comcast.net>
 <BYAPR04MB49659C0F0F0E11D166B31E0586A40@BYAPR04MB4965.namprd04.prod.outlook.com>
 <a4c75497-d170-1e0f-8608-282231ff3a8e@comcast.net>
 <BYAPR04MB496542BEF594F0380F7D41CF86A20@BYAPR04MB4965.namprd04.prod.outlook.com>
 <df46d7ce-ce70-1f43-0efd-7153761bcff0@comcast.net>
 <20210121124459.GA156577@localhost.localdomain>
 <96083ad4-e065-c071-bdc9-67517dc1e5a3@comcast.net>
Message-ID: <BYAPR04MB4965CCC3F7FCAEE6C0A60DFB86A00@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/21/21 6:32 PM, Bradley Chapman wrote:
> Thanks for the pointer. I've downloaded the code and will add it to a 
> stable 5.10 tree and a 5.11-rc tree and see what happens.
>
Please use the latest 5.12 branch and boot into the kernel.
If you can provide device's vendor ID and device ID I can cook up the
patch for you based on 5.12, will be waiting for your response.

These IDs can be found :-
cat  /sys/bus/pci/devices/<your device id>/device
cat  /sys/bus/pci/devices/<your device id>/vendor


From Chaitanya.Kulkarni at wdc.com  Thu Jan 21 21:54:17 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Fri, 22 Jan 2021 02:54:17 +0000
Subject: Problem with SPCC 256GB NVMe 1.3 drive - refcount_t: underflow;
 use-after-free.
References: <f50bc59c-db11-bb44-55be-7b9db1119872@comcast.net>
 <BYAPR04MB49659C0F0F0E11D166B31E0586A40@BYAPR04MB4965.namprd04.prod.outlook.com>
 <a4c75497-d170-1e0f-8608-282231ff3a8e@comcast.net>
 <BYAPR04MB496542BEF594F0380F7D41CF86A20@BYAPR04MB4965.namprd04.prod.outlook.com>
 <df46d7ce-ce70-1f43-0efd-7153761bcff0@comcast.net>
 <20210121124459.GA156577@localhost.localdomain>
 <96083ad4-e065-c071-bdc9-67517dc1e5a3@comcast.net>
Message-ID: <BYAPR04MB496526DA2E74A513E528D3E986A00@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/21/21 6:32 PM, Bradley Chapman wrote:
> Thanks for the pointer. I've downloaded the code and will add it to a 
> stable 5.10 tree and a 5.11-rc tree and see what happens.
>
Please use the latest 5.12 branch and boot into the kernel.
If you can provide device's vendor ID and device ID I can cook up the
patch for you based on 5.12, will be waiting for your response.

These IDs can be found :-
cat  /sys/bus/pci/devices/<your device id>/device
cat  /sys/bus/pci/devices/<your device id>/vendor



From chapman6235 at comcast.net  Thu Jan 21 21:54:29 2021
From: chapman6235 at comcast.net (Bradley Chapman)
Date: Thu, 21 Jan 2021 21:54:29 -0500
Subject: Problem with SPCC 256GB NVMe 1.3 drive - refcount_t: underflow;
 use-after-free.
In-Reply-To: <20210121124459.GA156577@localhost.localdomain>
References: <f50bc59c-db11-bb44-55be-7b9db1119872@comcast.net>
 <BYAPR04MB49659C0F0F0E11D166B31E0586A40@BYAPR04MB4965.namprd04.prod.outlook.com>
 <a4c75497-d170-1e0f-8608-282231ff3a8e@comcast.net>
 <BYAPR04MB496542BEF594F0380F7D41CF86A20@BYAPR04MB4965.namprd04.prod.outlook.com>
 <df46d7ce-ce70-1f43-0efd-7153761bcff0@comcast.net>
 <20210121124459.GA156577@localhost.localdomain>
Message-ID: <c48abecf-8e4f-b76a-c751-1a0d239c99b3@comcast.net>

Good evening!

On 1/21/21 7:45 AM, Niklas Cassel wrote:
> On Wed, Jan 20, 2021 at 09:33:08PM -0500, Bradley Chapman wrote:
>>>>> Also can you please also try the latest nvme tree branch nvme-5.11 ?
>>>>>
>>>> Where do I get that code from? Is it already in the 5.11-rc tree or do I
>>>> need to look somewhere else? I checked https://github.com/linux-nvme but
>>>> I did not see it there.
>>> Here is the link :-git://git.infradead.org/nvme.git
>>> Branch 5.12.
>>
>> I tried fetching the entire repo but it was huge and would have taken a long
>> time, so I tried to fetch a single branch instead and got this result:
>>
>> $ git clone --branch 5.12 --single-branch git://git.infradead.org/nvme.git
>> Cloning into 'nvme'...
>> warning: Could not find remote branch 5.12 to clone.
>> fatal: Remote branch 5.12 not found in upstream origin
>>
>> I haven't compiled any out-of-tree kernel code in a very long time - how
>> easy is it to add this code to a kernel tree and compile it into the kernel
>> once I've figured out how to get it?
> 
> Hello there,
> 
> You can see the available branches by replacing git:// with https:// i.e.:
> https://git.infradead.org/nvme.git
> 
> The branch is called nvme-5.12
> 
> It is not out-of-tree kernel code, it is a subsystem git tree,
> so you build the kernel like usual.
> 
> If you already have a kernel git tree somewhere,
> simply add an additional remote, and it should be quick:
> 
> $ git remote add nvme git://git.infradead.org/nvme.git && git fetch nvme
> 
> 
> Kind regards,
> Niklas
> 

I compiled the kernel from the above git tree, rebooted and attempted to 
mount the filesystem on the NVMe drive. This is what the kernel put into 
the dmesg when I attempted to list the contents of the filesystem root, 
create an inode for a zero-byte file and then unmount the filesystem.

Brad

<snip/>

[   52.795975] refcount_t: underflow; use-after-free.
[   52.795981] WARNING: CPU: 7 PID: 0 at lib/refcount.c:28 
refcount_warn_saturate+0xab/0xf0
[   52.795989] Modules linked in: rfcomm(E) cmac(E) bnep(E) 
binfmt_misc(E) nls_ascii(E) nls_cp437(E) vfat(E) fat(E) btusb(E) 
btrtl(E) btbcm(E) btintel(E) intel_rapl_common(E) iosf_mbi(E) 
crct10dif_pclmul(E) crc32_pclmul(E) bluetooth(E) ghash_clmulni_intel(E) 
rfkill(E) jitterentropy_rng(E) aesni_intel(E) crypto_simd(E) 
efi_pstore(E) cryptd(E) glue_helper(E) drbg(E) ccp(E) ansi_cprng(E) 
ecdh_generic(E) ecc(E) acpi_cpufreq(E) nft_counter(E) efivarfs(E) 
crc32c_intel(E)
[   52.796018] CPU: 7 PID: 0 Comm: swapper/7 Tainted: G            E 
  5.11.0-rc1-BET+ #1
[   52.796021] Hardware name: System manufacturer System Product 
Name/PRIME X570-P, BIOS 3001 12/04/2020
[   52.796023] RIP: 0010:refcount_warn_saturate+0xab/0xf0
[   52.796026] Code: 05 02 a0 72 01 01 e8 49 7d 8b 00 0f 0b c3 80 3d f0 
9f 72 01 00 75 90 48 c7 c7 88 4c c7 8a c6 05 e0 9f 72 01 01 e8 2a 7d 8b 
00 <0f> 0b c3 80 3d cf 9f 72 01 00 0f 85 6d ff ff ff 48 c7 c7 e0 4c c7
[   52.796028] RSP: 0018:ffffa95b80374f28 EFLAGS: 00010082
[   52.796031] RAX: 0000000000000000 RBX: ffff9ac74f014800 RCX: 
0000000000000027
[   52.796032] RDX: 0000000000000027 RSI: ffff9ace4ebd2ed0 RDI: 
ffff9ace4ebd2ed8
[   52.796034] RBP: ffff9ac753820080 R08: 0000000000000000 R09: 
c0000000ffffdfff
[   52.796035] R10: ffffa95b80374d48 R11: ffffa95b80374d40 R12: 
0000000000000001
[   52.796037] R13: ffff9ac7539e2100 R14: 0000000000000016 R15: 
0000000000000000
[   52.796038] FS:  0000000000000000(0000) GS:ffff9ace4ebc0000(0000) 
knlGS:0000000000000000
[   52.796040] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   52.796042] CR2: 00007f3eb6493000 CR3: 00000006afe12000 CR4: 
0000000000350ee0
[   52.796043] Call Trace:
[   52.796045]  <IRQ>
[   52.796046]  nvme_irq+0x10b/0x190
[   52.796052]  __handle_irq_event_percpu+0x2e/0xd0
[   52.796056]  handle_irq_event_percpu+0x33/0x80
[   52.796058]  handle_irq_event+0x39/0x70
[   52.796060]  handle_edge_irq+0x7c/0x1a0
[   52.796064]  asm_call_irq_on_stack+0x12/0x20
[   52.796068]  </IRQ>
[   52.796069]  common_interrupt+0xd7/0x160
[   52.796073]  asm_common_interrupt+0x1e/0x40
[   52.796076] RIP: 0010:cpuidle_enter_state+0xd2/0x2e0
[   52.796080] Code: e8 73 ca 65 ff 31 ff 49 89 c5 e8 09 d4 65 ff 45 84 
ff 74 12 9c 58 f6 c4 02 0f 85 c4 01 00 00 31 ff e8 d2 8a 6b ff fb 45 85 
f6 <0f> 88 c9 00 00 00 49 63 ce be 68 00 00 00 4c 2b 2c 24 48 89 ca 48
[   52.796082] RSP: 0018:ffffa95b80177e80 EFLAGS: 00000202
[   52.796084] RAX: ffff9ace4ebdce80 RBX: 0000000000000002 RCX: 
000000000000001f
[   52.796085] RDX: 0000000c4ae2908c RSI: 00000000239f5229 RDI: 
0000000000000000
[   52.796086] RBP: ffff9ac74e561400 R08: 0000000000000002 R09: 
000000000001c680
[   52.796088] R10: 0000003ae7504a4c R11: ffff9ace4ebdbe64 R12: 
ffffffff8aed3d20
[   52.796089] R13: 0000000c4ae2908c R14: 0000000000000002 R15: 
0000000000000000
[   52.796092]  cpuidle_enter+0x30/0x50
[   52.796095]  do_idle+0x24f/0x290
[   52.796098]  cpu_startup_entry+0x1b/0x20
[   52.796100]  start_secondary+0x11b/0x160
[   52.796103]  secondary_startup_64_no_verify+0xb0/0xbb
[   52.796107] ---[ end trace a0a237d707896b40 ]---
[   82.811599] nvme nvme1: I/O 7 QID 8 timeout, aborting
[   82.811613] nvme nvme1: I/O 8 QID 8 timeout, aborting
[   82.811617] nvme nvme1: I/O 9 QID 8 timeout, aborting
[   82.811622] nvme nvme1: I/O 10 QID 8 timeout, aborting
[   82.811650] nvme nvme1: Abort status: 0x0
[   82.811665] nvme nvme1: Abort status: 0x0
[   82.811668] nvme nvme1: Abort status: 0x0
[   82.811670] nvme nvme1: Abort status: 0x0
[  113.019489] nvme nvme1: I/O 7 QID 8 timeout, reset controller
[  113.037771] nvme nvme1: 15/0/0 default/read/poll queues
[  143.228062] nvme nvme1: I/O 8 QID 8 timeout, disable controller
[  143.346027] blk_update_request: I/O error, dev nvme1n1, sector 16350 
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[  143.346039] blk_update_request: I/O error, dev nvme1n1, sector 16093 
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[  143.346044] blk_update_request: I/O error, dev nvme1n1, sector 15836 
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[  143.346047] blk_update_request: I/O error, dev nvme1n1, sector 15579 
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[  143.346049] blk_update_request: I/O error, dev nvme1n1, sector 15322 
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[  143.346052] blk_update_request: I/O error, dev nvme1n1, sector 15065 
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[  143.346055] blk_update_request: I/O error, dev nvme1n1, sector 14808 
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[  143.346057] blk_update_request: I/O error, dev nvme1n1, sector 14551 
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[  143.346060] blk_update_request: I/O error, dev nvme1n1, sector 14294 
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[  143.346063] blk_update_request: I/O error, dev nvme1n1, sector 14037 
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[  143.346116] nvme nvme1: failed to mark controller live state
[  143.346120] nvme nvme1: Removing after probe failure status: -19
[  143.351776] nvme1n1: detected capacity change from 0 to 500118192
[  143.351836] Aborting journal on device dm-0-8.
[  143.351842] Buffer I/O error on dev dm-0, logical block 25198592, 
lost sync page write
[  143.351846] JBD2: Error -5 detected when updating journal superblock 
for dm-0-8.
[  181.098750] EXT4-fs error (device dm-0): ext4_read_inode_bitmap:203: 
comm touch: Cannot read inode bitmap - block_group = 0, inode_bitmap = 1065
[  181.098792] Buffer I/O error on dev dm-0, logical block 0, lost sync 
page write
[  181.098800] EXT4-fs (dm-0): I/O error while writing superblock
[  181.098806] EXT4-fs error (device dm-0): ext4_journal_check_start:83: 
comm touch: Detected aborted journal
[  181.098811] Buffer I/O error on dev dm-0, logical block 0, lost sync 
page write
[  181.098817] EXT4-fs (dm-0): I/O error while writing superblock
[  181.098819] EXT4-fs (dm-0): Remounting filesystem read-only


From Chaitanya.Kulkarni at wdc.com  Thu Jan 21 21:57:49 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Fri, 22 Jan 2021 02:57:49 +0000
Subject: Problem with SPCC 256GB NVMe 1.3 drive - refcount_t: underflow;
 use-after-free.
References: <f50bc59c-db11-bb44-55be-7b9db1119872@comcast.net>
 <BYAPR04MB49659C0F0F0E11D166B31E0586A40@BYAPR04MB4965.namprd04.prod.outlook.com>
 <a4c75497-d170-1e0f-8608-282231ff3a8e@comcast.net>
 <BYAPR04MB496542BEF594F0380F7D41CF86A20@BYAPR04MB4965.namprd04.prod.outlook.com>
 <df46d7ce-ce70-1f43-0efd-7153761bcff0@comcast.net>
 <20210121124459.GA156577@localhost.localdomain>
 <c48abecf-8e4f-b76a-c751-1a0d239c99b3@comcast.net>
Message-ID: <BYAPR04MB4965404638B4C43DBA577D1686A00@BYAPR04MB4965.namprd04.prod.outlook.com>

Bradley,

On 1/21/21 6:54 PM, Bradley Chapman wrote:
> I compiled the kernel from the above git tree, rebooted and attempted to 
> mount the filesystem on the NVMe drive. This is what the kernel put into 
> the dmesg when I attempted to list the contents of the filesystem root, 
> create an inode for a zero-byte file and then unmount the filesystem.
>
> Brad
Did you get a chance to see my response to your previous email ?


From Chaitanya.Kulkarni at wdc.com  Thu Jan 21 22:16:09 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Fri, 22 Jan 2021 03:16:09 +0000
Subject: Problem with SPCC 256GB NVMe 1.3 drive - refcount_t: underflow;
 use-after-free.
References: <f50bc59c-db11-bb44-55be-7b9db1119872@comcast.net>
 <BYAPR04MB49659C0F0F0E11D166B31E0586A40@BYAPR04MB4965.namprd04.prod.outlook.com>
 <a4c75497-d170-1e0f-8608-282231ff3a8e@comcast.net>
 <BYAPR04MB496542BEF594F0380F7D41CF86A20@BYAPR04MB4965.namprd04.prod.outlook.com>
 <df46d7ce-ce70-1f43-0efd-7153761bcff0@comcast.net>
 <20210121124459.GA156577@localhost.localdomain>
 <c48abecf-8e4f-b76a-c751-1a0d239c99b3@comcast.net>
 <BYAPR04MB4965404638B4C43DBA577D1686A00@BYAPR04MB4965.namprd04.prod.outlook.com>
Message-ID: <BYAPR04MB4965342B52D5C3C6D8A7892D86A00@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/21/21 6:57 PM, Chaitanya Kulkarni wrote:
> Bradley,
>
> On 1/21/21 6:54 PM, Bradley Chapman wrote:
>> I compiled the kernel from the above git tree, rebooted and attempted to 
>> mount the filesystem on the NVMe drive. This is what the kernel put into 
>> the dmesg when I attempted to list the contents of the filesystem root, 
>> create an inode for a zero-byte file and then unmount the filesystem.
>>
>> Brad
> Did you get a chance to see my response to your previous email ?
>
You can try following patch with some modification :-

>From e162a2e91e4895ceac6f80042a87c4ba6a4fbbf5 Mon Sep 17 00:00:00 2001
From: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
Date: Thu, 21 Jan 2021 19:05:13 -0800
Subject: [PATCH] nvme-pci: add device quirk wip

This is work in progress patch which is based on nvme-5.12
HEAD : b116d37fc0f5 nvmet: add lba to sect conversion helpers

Replace <YOUR DEVICE'S VENDOR ID> and <YOUR DEVICE's DEVICE ID> with
actual values sysfs entries in patch below before you apply the patch :-

cat  /sys/bus/pci/devices/<your device id>/device
cat  /sys/bus/pci/devices/<your device id>/vendor

This patch is not tested at all.

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/host/pci.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 25456d02eddb..c5b43bcf57b0 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -3228,6 +3228,8 @@ static const struct pci_device_id nvme_id_table[] = {
         .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
     { PCI_DEVICE(0x15b7, 0x2001),   /*  Sandisk Skyhawk */
         .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
+    { PCI_DEVICE(<YOUR DEVICE's VENDOR ID>, <YOUR DEVICE's DEVICE ID>),
+        .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
     { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2001),
         .driver_data = NVME_QUIRK_SINGLE_VECTOR },
     { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2003) },
-- 
2.22.1





From guoqing.jiang at cloud.ionos.com  Fri Jan 22 02:36:45 2021
From: guoqing.jiang at cloud.ionos.com (Guoqing Jiang)
Date: Fri, 22 Jan 2021 08:36:45 +0100
Subject: [PATCH 1/2] block: remove unnecessary argument from
 blk_execute_rq_nowait
In-Reply-To: <20210121170257.GA4120717@infradead.org>
References: <20210121142905.13089-1-guoqing.jiang@cloud.ionos.com>
 <20210121142905.13089-2-guoqing.jiang@cloud.ionos.com>
 <20210121170257.GA4120717@infradead.org>
Message-ID: <b87591b9-e598-6436-d41f-80cc56640549@cloud.ionos.com>



On 1/21/21 18:02, Christoph Hellwig wrote:
> On Thu, Jan 21, 2021 at 03:29:04PM +0100, Guoqing Jiang wrote:
>> The 'q' is not used since commit a1ce35fa4985 ("block: remove dead
>> elevator code"), also update the comment of the function.
> 
> And more importantly it never really was needed to start with given
> that we can triviall derive it from struct request.

Thanks Christoph, will add the above to header and send new version.

Guoqing


From damien.lemoal at wdc.com  Fri Jan 22 03:00:11 2021
From: damien.lemoal at wdc.com (Damien Le Moal)
Date: Fri, 22 Jan 2021 17:00:11 +0900
Subject: [PATCH v3 0/3] block: add zone write granularity limit
Message-ID: <20210122080014.174391-1-damien.lemoal@wdc.com>

The first patch in this series introduces the zone write granularity
queue limit to indicate the alignment constraint for write operations
into sequential zones of zoned block devices.

The second patch fixes adds the missing documentation for
zone_append_max_bytes to the sysfs block documentation.

The third patch switch zonefs to use this new limit as the file block
size instead of using the physical block size.

Changes from v2:
* Added patch 3 for zonefs
* Addressed Christoph's comments on patch 1 and added the limit
  initialization for zoned nullblk

Changes from v1:
* Fixed typo in patch 2

Damien Le Moal (3):
  block: introduce zone_write_granularity limit
  block: document zone_append_max_bytes attribute
  zonefs: use zone write granularity as block size

 Documentation/block/queue-sysfs.rst | 13 ++++++++++
 block/blk-settings.c                | 39 +++++++++++++++++++++++++----
 block/blk-sysfs.c                   |  8 ++++++
 drivers/block/null_blk/zoned.c      |  1 +
 drivers/nvme/host/zns.c             |  1 +
 drivers/scsi/sd_zbc.c               | 10 ++++++++
 fs/zonefs/super.c                   |  9 +++----
 include/linux/blkdev.h              | 15 +++++++++++
 8 files changed, 86 insertions(+), 10 deletions(-)

-- 
2.29.2



From damien.lemoal at wdc.com  Fri Jan 22 03:00:12 2021
From: damien.lemoal at wdc.com (Damien Le Moal)
Date: Fri, 22 Jan 2021 17:00:12 +0900
Subject: [PATCH v3 1/3] block: introduce zone_write_granularity limit
In-Reply-To: <20210122080014.174391-1-damien.lemoal@wdc.com>
References: <20210122080014.174391-1-damien.lemoal@wdc.com>
Message-ID: <20210122080014.174391-2-damien.lemoal@wdc.com>

Per ZBC and ZAC specifications, host-managed SMR hard-disks mandate that
all writes into sequential write required zones be aligned to the device
physical block size. However, NVMe ZNS does not have this constraint and
allows write operations into sequential zones to be logical block size
aligned. This inconsistency does not help with portability of software
across device types.
To solve this, introduce the zone_write_granularity queue limit to
indicate the alignment constraint, in bytes, of write operations into
zones of a zoned block device. This new limit is exported as a
read-only sysfs queue attribute and the helper
blk_queue_zone_write_granularity() introduced for drivers to set this
limit. The scsi disk driver is modified to use this helper to set
host-managed SMR disk zone write granularity to the disk physical block
size. The ZNS support code of the NVMe driver is also modified to use
this helper to set the new limit to the logical block size of the
namespace. The nullblk driver is similarly modified too.

The accessor functions queue_zone_write_granularity() and
bdev_zone_write_granularity() are also introduced.

Signed-off-by: Damien Le Moal <damien.lemoal at wdc.com>
---
 Documentation/block/queue-sysfs.rst |  7 ++++++
 block/blk-settings.c                | 39 +++++++++++++++++++++++++----
 block/blk-sysfs.c                   |  8 ++++++
 drivers/block/null_blk/zoned.c      |  1 +
 drivers/nvme/host/zns.c             |  1 +
 drivers/scsi/sd_zbc.c               | 10 ++++++++
 include/linux/blkdev.h              | 15 +++++++++++
 7 files changed, 76 insertions(+), 5 deletions(-)

diff --git a/Documentation/block/queue-sysfs.rst b/Documentation/block/queue-sysfs.rst
index 2638d3446b79..c8bf8bc3c03a 100644
--- a/Documentation/block/queue-sysfs.rst
+++ b/Documentation/block/queue-sysfs.rst
@@ -273,4 +273,11 @@ devices are described in the ZBC (Zoned Block Commands) and ZAC
 do not support zone commands, they will be treated as regular block devices
 and zoned will report "none".
 
+zone_write_granularity (RO)
+---------------------------
+This indicates the alignment constraint, in bytes, for write operations in
+sequential zones of zoned block devices (devices with a zoned attributed
+that reports "host-managed" or "host-aware"). This value is always 0 for
+regular block devices.
+
 Jens Axboe <jens.axboe at oracle.com>, February 2009
diff --git a/block/blk-settings.c b/block/blk-settings.c
index 43990b1d148b..48872b4085d4 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -60,6 +60,7 @@ void blk_set_default_limits(struct queue_limits *lim)
 	lim->io_opt = 0;
 	lim->misaligned = 0;
 	lim->zoned = BLK_ZONED_NONE;
+	lim->zone_write_granularity = 0;
 }
 EXPORT_SYMBOL(blk_set_default_limits);
 
@@ -366,6 +367,28 @@ void blk_queue_physical_block_size(struct request_queue *q, unsigned int size)
 }
 EXPORT_SYMBOL(blk_queue_physical_block_size);
 
+/**
+ * blk_queue_zone_write_granularity - set zone write granularity for the queue
+ * @q:  the request queue for the zoned device
+ * @size:  the zone write granularity size, in bytes
+ *
+ * Description:
+ *   This should be set to the lowest possible size allowing to write in
+ *   sequential zones of a zoned block device.
+ */
+void blk_queue_zone_write_granularity(struct request_queue *q,
+				      unsigned int size)
+{
+	if (WARN_ON_ONCE(!blk_queue_is_zoned(q)))
+		return;
+
+	q->limits.zone_write_granularity = size;
+
+	if (q->limits.zone_write_granularity < q->limits.logical_block_size)
+		q->limits.zone_write_granularity = q->limits.logical_block_size;
+}
+EXPORT_SYMBOL_GPL(blk_queue_zone_write_granularity);
+
 /**
  * blk_queue_alignment_offset - set physical block alignment offset
  * @q:	the request queue for the device
@@ -631,6 +654,8 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
 			t->discard_granularity;
 	}
 
+	t->zone_write_granularity = max(t->zone_write_granularity,
+					b->zone_write_granularity);
 	t->zoned = max(t->zoned, b->zoned);
 	return ret;
 }
@@ -847,6 +872,8 @@ EXPORT_SYMBOL_GPL(blk_queue_can_use_dma_map_merging);
  */
 void blk_queue_set_zoned(struct gendisk *disk, enum blk_zoned_model model)
 {
+	struct request_queue *q = disk->queue;
+
 	switch (model) {
 	case BLK_ZONED_HM:
 		/*
@@ -864,18 +891,20 @@ void blk_queue_set_zoned(struct gendisk *disk, enum blk_zoned_model model)
 		 * partitions and zoned block device support is enabled, else
 		 * we do nothing special as far as the block layer is concerned.
 		 */
-		if (!IS_ENABLED(CONFIG_BLK_DEV_ZONED) ||
-		    disk_has_partitions(disk))
-			model = BLK_ZONED_NONE;
-		break;
+		if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) &&
+		    !disk_has_partitions(disk))
+			break;
+		model = BLK_ZONED_NONE;
+		fallthrough;
 	case BLK_ZONED_NONE:
 	default:
 		if (WARN_ON_ONCE(model != BLK_ZONED_NONE))
 			model = BLK_ZONED_NONE;
+		q->limits.zone_write_granularity = 0;
 		break;
 	}
 
-	disk->queue->limits.zoned = model;
+	q->limits.zoned = model;
 }
 EXPORT_SYMBOL_GPL(blk_queue_set_zoned);
 
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index b513f1683af0..ae39c7f3d83d 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -219,6 +219,12 @@ static ssize_t queue_write_zeroes_max_show(struct request_queue *q, char *page)
 		(unsigned long long)q->limits.max_write_zeroes_sectors << 9);
 }
 
+static ssize_t queue_zone_write_granularity_show(struct request_queue *q,
+						 char *page)
+{
+	return queue_var_show(queue_zone_write_granularity(q), page);
+}
+
 static ssize_t queue_zone_append_max_show(struct request_queue *q, char *page)
 {
 	unsigned long long max_sectors = q->limits.max_zone_append_sectors;
@@ -585,6 +591,7 @@ QUEUE_RO_ENTRY(queue_discard_zeroes_data, "discard_zeroes_data");
 QUEUE_RO_ENTRY(queue_write_same_max, "write_same_max_bytes");
 QUEUE_RO_ENTRY(queue_write_zeroes_max, "write_zeroes_max_bytes");
 QUEUE_RO_ENTRY(queue_zone_append_max, "zone_append_max_bytes");
+QUEUE_RO_ENTRY(queue_zone_write_granularity, "zone_write_granularity");
 
 QUEUE_RO_ENTRY(queue_zoned, "zoned");
 QUEUE_RO_ENTRY(queue_nr_zones, "nr_zones");
@@ -639,6 +646,7 @@ static struct attribute *queue_attrs[] = {
 	&queue_write_same_max_entry.attr,
 	&queue_write_zeroes_max_entry.attr,
 	&queue_zone_append_max_entry.attr,
+	&queue_zone_write_granularity_entry.attr,
 	&queue_nonrot_entry.attr,
 	&queue_zoned_entry.attr,
 	&queue_nr_zones_entry.attr,
diff --git a/drivers/block/null_blk/zoned.c b/drivers/block/null_blk/zoned.c
index 535351570bb2..704d09481e0d 100644
--- a/drivers/block/null_blk/zoned.c
+++ b/drivers/block/null_blk/zoned.c
@@ -172,6 +172,7 @@ int null_register_zoned_dev(struct nullb *nullb)
 	blk_queue_max_zone_append_sectors(q, dev->zone_size_sects);
 	blk_queue_max_open_zones(q, dev->zone_max_open);
 	blk_queue_max_active_zones(q, dev->zone_max_active);
+	blk_queue_zone_write_granularity(q, dev->blocksize);
 
 	return 0;
 }
diff --git a/drivers/nvme/host/zns.c b/drivers/nvme/host/zns.c
index 1dfe9a3500e3..f25311ccd996 100644
--- a/drivers/nvme/host/zns.c
+++ b/drivers/nvme/host/zns.c
@@ -113,6 +113,7 @@ int nvme_update_zone_info(struct nvme_ns *ns, unsigned lbaf)
 	blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, q);
 	blk_queue_max_open_zones(q, le32_to_cpu(id->mor) + 1);
 	blk_queue_max_active_zones(q, le32_to_cpu(id->mar) + 1);
+	blk_queue_zone_write_granularity(q, q->limits.logical_block_size);
 free_data:
 	kfree(id);
 	return status;
diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c
index cf07b7f93579..10e9f33cc069 100644
--- a/drivers/scsi/sd_zbc.c
+++ b/drivers/scsi/sd_zbc.c
@@ -789,6 +789,16 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf)
 	blk_queue_max_active_zones(q, 0);
 	nr_zones = round_up(sdkp->capacity, zone_blocks) >> ilog2(zone_blocks);
 
+	/*
+	 * Per ZBC and ZAC specifications, writes in sequential write required
+	 * zones of host-managed devices must be aligned to the device physical
+	 * block size.
+	 */
+	if (blk_queue_zoned_model(q) == BLK_ZONED_HM)
+		blk_queue_zone_write_granularity(q, sdkp->physical_block_size);
+	else if (blk_queue_zoned_model(q) == BLK_ZONED_HA)
+		blk_queue_zone_write_granularity(q, sdkp->device->sector_size);
+
 	/* READ16/WRITE16 is mandatory for ZBC disks */
 	sdkp->device->use_16_for_rw = 1;
 	sdkp->device->use_10_for_rw = 0;
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index f94ee3089e01..142e3b34be75 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -337,6 +337,7 @@ struct queue_limits {
 	unsigned int		max_zone_append_sectors;
 	unsigned int		discard_granularity;
 	unsigned int		discard_alignment;
+	unsigned int		zone_write_granularity;
 
 	unsigned short		max_segments;
 	unsigned short		max_integrity_segments;
@@ -1161,6 +1162,8 @@ extern void blk_queue_logical_block_size(struct request_queue *, unsigned int);
 extern void blk_queue_max_zone_append_sectors(struct request_queue *q,
 		unsigned int max_zone_append_sectors);
 extern void blk_queue_physical_block_size(struct request_queue *, unsigned int);
+void blk_queue_zone_write_granularity(struct request_queue *q,
+				      unsigned int size);
 extern void blk_queue_alignment_offset(struct request_queue *q,
 				       unsigned int alignment);
 void blk_queue_update_readahead(struct request_queue *q);
@@ -1474,6 +1477,18 @@ static inline int bdev_io_opt(struct block_device *bdev)
 	return queue_io_opt(bdev_get_queue(bdev));
 }
 
+static inline unsigned int
+queue_zone_write_granularity(const struct request_queue *q)
+{
+	return q->limits.zone_write_granularity;
+}
+
+static inline unsigned int
+bdev_zone_write_granularity(struct block_device *bdev)
+{
+	return queue_zone_write_granularity(bdev_get_queue(bdev));
+}
+
 static inline int queue_alignment_offset(const struct request_queue *q)
 {
 	if (q->limits.misaligned)
-- 
2.29.2



From damien.lemoal at wdc.com  Fri Jan 22 03:00:13 2021
From: damien.lemoal at wdc.com (Damien Le Moal)
Date: Fri, 22 Jan 2021 17:00:13 +0900
Subject: [PATCH v3 2/3] block: document zone_append_max_bytes attribute
In-Reply-To: <20210122080014.174391-1-damien.lemoal@wdc.com>
References: <20210122080014.174391-1-damien.lemoal@wdc.com>
Message-ID: <20210122080014.174391-3-damien.lemoal@wdc.com>

The description of the zone_append_max_bytes sysfs queue attribute is
missing from Documentation/block/queue-sysfs.rst. Add it.

Signed-off-by: Damien Le Moal <damien.lemoal at wdc.com>
Reviewed-by: Christoph Hellwig <hch at lst.de>
---
 Documentation/block/queue-sysfs.rst | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/block/queue-sysfs.rst b/Documentation/block/queue-sysfs.rst
index c8bf8bc3c03a..4dc7f0d499a8 100644
--- a/Documentation/block/queue-sysfs.rst
+++ b/Documentation/block/queue-sysfs.rst
@@ -261,6 +261,12 @@ For block drivers that support REQ_OP_WRITE_ZEROES, the maximum number of
 bytes that can be zeroed at once. The value 0 means that REQ_OP_WRITE_ZEROES
 is not supported.
 
+zone_append_max_bytes (RO)
+--------------------------
+This is the maximum number of bytes that can be written to a sequential
+zone of a zoned block device using a zone append write operation
+(REQ_OP_ZONE_APPEND). This value is always 0 for regular block devices.
+
 zoned (RO)
 ----------
 This indicates if the device is a zoned block device and the zone model of the
-- 
2.29.2



From damien.lemoal at wdc.com  Fri Jan 22 03:00:14 2021
From: damien.lemoal at wdc.com (Damien Le Moal)
Date: Fri, 22 Jan 2021 17:00:14 +0900
Subject: [PATCH v3 3/3] zonefs: use zone write granularity as block size
In-Reply-To: <20210122080014.174391-1-damien.lemoal@wdc.com>
References: <20210122080014.174391-1-damien.lemoal@wdc.com>
Message-ID: <20210122080014.174391-4-damien.lemoal@wdc.com>

Zoned block devices have different granularity constraints for write
operations into sequential zones. E.g. ZBC and ZAC devices require that
writes be aligned to the device physical block size while NVMe ZNS
devices allow logical block size aligned write operations. To correctly
handle such difference, use the device zone write granularity limit to
set the block size of a zonefs volume, thus allowing the smallest
possible write unit for all zoned device types.

Signed-off-by: Damien Le Moal <damien.lemoal at wdc.com>
---
 fs/zonefs/super.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/fs/zonefs/super.c b/fs/zonefs/super.c
index bec47f2d074b..8973d77ba000 100644
--- a/fs/zonefs/super.c
+++ b/fs/zonefs/super.c
@@ -1581,12 +1581,11 @@ static int zonefs_fill_super(struct super_block *sb, void *data, int silent)
 	sb->s_time_gran	= 1;
 
 	/*
-	 * The block size is set to the device physical sector size to ensure
-	 * that write operations on 512e devices (512B logical block and 4KB
-	 * physical block) are always aligned to the device physical blocks,
-	 * as mandated by the ZBC/ZAC specifications.
+	 * The block size is set to the device zone write granularity to ensure
+	 * that write operations are always aligned according to the device
+	 * interface constraints.
 	 */
-	sb_set_blocksize(sb, bdev_physical_block_size(sb->s_bdev));
+	sb_set_blocksize(sb, bdev_zone_write_granularity(sb->s_bdev));
 	sbi->s_zone_sectors_shift = ilog2(bdev_zone_sectors(sb->s_bdev));
 	sbi->s_uid = GLOBAL_ROOT_UID;
 	sbi->s_gid = GLOBAL_ROOT_GID;
-- 
2.29.2



From hch at lst.de  Fri Jan 22 03:42:09 2021
From: hch at lst.de (Christoph Hellwig)
Date: Fri, 22 Jan 2021 09:42:09 +0100
Subject: [PATCH v3 1/3] block: introduce zone_write_granularity limit
In-Reply-To: <20210122080014.174391-2-damien.lemoal@wdc.com>
References: <20210122080014.174391-1-damien.lemoal@wdc.com>
 <20210122080014.174391-2-damien.lemoal@wdc.com>
Message-ID: <20210122084209.GA15710@lst.de>

> @@ -864,18 +891,20 @@ void blk_queue_set_zoned(struct gendisk *disk, enum blk_zoned_model model)
>  		 * partitions and zoned block device support is enabled, else
>  		 * we do nothing special as far as the block layer is concerned.
>  		 */
> -		if (!IS_ENABLED(CONFIG_BLK_DEV_ZONED) ||
> -		    disk_has_partitions(disk))
> -			model = BLK_ZONED_NONE;
> -		break;
> +		if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) &&
> +		    !disk_has_partitions(disk))
> +			break;
> +		model = BLK_ZONED_NONE;
> +		fallthrough;
>  	case BLK_ZONED_NONE:
>  	default:
>  		if (WARN_ON_ONCE(model != BLK_ZONED_NONE))
>  			model = BLK_ZONED_NONE;
> +		q->limits.zone_write_granularity = 0;
>  		break;
>  	}
>  
> -	disk->queue->limits.zoned = model;
> +	q->limits.zoned = model;
>  }

This looks a little strange.  If we special case zoned vs not zoned
here anyway, why not set the zone_write_granularity to the logical
block size here by default.


From hch at lst.de  Fri Jan 22 03:42:31 2021
From: hch at lst.de (Christoph Hellwig)
Date: Fri, 22 Jan 2021 09:42:31 +0100
Subject: [PATCH v3 3/3] zonefs: use zone write granularity as block size
In-Reply-To: <20210122080014.174391-4-damien.lemoal@wdc.com>
References: <20210122080014.174391-1-damien.lemoal@wdc.com>
 <20210122080014.174391-4-damien.lemoal@wdc.com>
Message-ID: <20210122084231.GB15710@lst.de>

Looks good,

Reviewed-by: Christoph Hellwig <hch at lst.de>


From Damien.LeMoal at wdc.com  Fri Jan 22 03:56:58 2021
From: Damien.LeMoal at wdc.com (Damien Le Moal)
Date: Fri, 22 Jan 2021 08:56:58 +0000
Subject: [PATCH v3 1/3] block: introduce zone_write_granularity limit
References: <20210122080014.174391-1-damien.lemoal@wdc.com>
 <20210122080014.174391-2-damien.lemoal@wdc.com>
 <20210122084209.GA15710@lst.de>
Message-ID: <BL0PR04MB6514A2655635DFF482E4252BE7A00@BL0PR04MB6514.namprd04.prod.outlook.com>

On 2021/01/22 17:42, Christoph Hellwig wrote:
>> @@ -864,18 +891,20 @@ void blk_queue_set_zoned(struct gendisk *disk, enum blk_zoned_model model)
>>  		 * partitions and zoned block device support is enabled, else
>>  		 * we do nothing special as far as the block layer is concerned.
>>  		 */
>> -		if (!IS_ENABLED(CONFIG_BLK_DEV_ZONED) ||
>> -		    disk_has_partitions(disk))
>> -			model = BLK_ZONED_NONE;
>> -		break;
>> +		if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) &&
>> +		    !disk_has_partitions(disk))
>> +			break;
>> +		model = BLK_ZONED_NONE;
>> +		fallthrough;
>>  	case BLK_ZONED_NONE:
>>  	default:
>>  		if (WARN_ON_ONCE(model != BLK_ZONED_NONE))
>>  			model = BLK_ZONED_NONE;
>> +		q->limits.zone_write_granularity = 0;
>>  		break;
>>  	}
>>  
>> -	disk->queue->limits.zoned = model;
>> +	q->limits.zoned = model;
>>  }
> 
> This looks a little strange.  If we special case zoned vs not zoned
> here anyway, why not set the zone_write_granularity to the logical
> block size here by default.

The convention is zone_write_granularity == 0 for the BLK_ZONED_NONE case. Hence
the reset here if we force the zoned model to none for HA drives. This way, this
does not create a special case for HA drives used as regular disks.

Of note is that there is something a little weird in the sd_zbc.c code that
needs fixing: blk_queue_set_zoned() is called before sd_zbc_read_zones() is
executed and that function will check the zones of an HA drive and set the queue
nr_zones and max zone append sectors, even if blk_queue_set_zoned() set the
zoned model to none due to partitions. That makes the BLK_ZONED_NONE case of HA
drives a little weird since zone information is visible and correct but the
model says "none". As long as users separate zoned vs not-zoned cases by looking
at the zoned model, this does not create any problem, but that is not pretty.

Will send a separate patch to clean that up and have something consistent with
regular disks for this special HA case. The above blk_queue_set_zoned() function
can be used to cleanup the zones information for an HA drive that is used as a
regular disk (nr_zones, zone append sectors and zone bitmaps).


-- 
Damien Le Moal
Western Digital Research


From guoqing.jiang at cloud.ionos.com  Fri Jan 22 04:28:22 2021
From: guoqing.jiang at cloud.ionos.com (Guoqing Jiang)
Date: Fri, 22 Jan 2021 10:28:22 +0100
Subject: [PATCH V2 0/2] remove unused argument from blk_execute_rq_nowait and
 blk_execute_rq
Message-ID: <20210122092824.20971-1-guoqing.jiang@cloud.ionos.com>

V2 changes:
1. update commit header per Christoph's comment.

Hi Jens,

This series remove unused 'q' from blk_execute_rq_nowait and blk_execute_rq.
Also update the comment for blk_execute_rq_nowait.

Thanks,
Guoqing

Guoqing Jiang (2):
  block: remove unnecessary argument from blk_execute_rq_nowait
  block: remove unnecessary argument from blk_execute_rq

 block/blk-exec.c                   | 13 +++++--------
 block/bsg.c                        |  2 +-
 block/scsi_ioctl.c                 |  6 +++---
 drivers/block/mtip32xx/mtip32xx.c  |  2 +-
 drivers/block/paride/pd.c          |  2 +-
 drivers/block/pktcdvd.c            |  2 +-
 drivers/block/sx8.c                |  4 ++--
 drivers/block/virtio_blk.c         |  2 +-
 drivers/cdrom/cdrom.c              |  2 +-
 drivers/ide/ide-atapi.c            |  2 +-
 drivers/ide/ide-cd.c               |  2 +-
 drivers/ide/ide-cd_ioctl.c         |  2 +-
 drivers/ide/ide-devsets.c          |  2 +-
 drivers/ide/ide-disk.c             |  2 +-
 drivers/ide/ide-ioctls.c           |  4 ++--
 drivers/ide/ide-park.c             |  2 +-
 drivers/ide/ide-pm.c               |  4 ++--
 drivers/ide/ide-tape.c             |  2 +-
 drivers/ide/ide-taskfile.c         |  2 +-
 drivers/mmc/core/block.c           | 10 +++++-----
 drivers/nvme/host/core.c           |  8 ++++----
 drivers/nvme/host/lightnvm.c       |  4 ++--
 drivers/nvme/host/pci.c            |  4 ++--
 drivers/nvme/target/passthru.c     |  2 +-
 drivers/scsi/scsi_error.c          |  2 +-
 drivers/scsi/scsi_lib.c            |  2 +-
 drivers/scsi/sg.c                  |  3 +--
 drivers/scsi/st.c                  |  2 +-
 drivers/target/target_core_pscsi.c |  3 +--
 fs/nfsd/blocklayout.c              |  2 +-
 include/linux/blkdev.h             |  5 ++---
 31 files changed, 50 insertions(+), 56 deletions(-)

-- 
2.17.1



From guoqing.jiang at cloud.ionos.com  Fri Jan 22 04:28:23 2021
From: guoqing.jiang at cloud.ionos.com (Guoqing Jiang)
Date: Fri, 22 Jan 2021 10:28:23 +0100
Subject: [PATCH V2 1/2] block: remove unnecessary argument from
 blk_execute_rq_nowait
In-Reply-To: <20210122092824.20971-1-guoqing.jiang@cloud.ionos.com>
References: <20210122092824.20971-1-guoqing.jiang@cloud.ionos.com>
Message-ID: <20210122092824.20971-2-guoqing.jiang@cloud.ionos.com>

The 'q' is not used since commit a1ce35fa4985 ("block: remove dead
elevator code"), also update the comment of the function.

And more importantly it never really was needed to start with given
that we can trivial derive it from struct request.

Cc: target-devel at vger.kernel.org
Cc: linux-scsi at vger.kernel.org
Cc: virtualization at lists.linux-foundation.org
Cc: linux-ide at vger.kernel.org
Cc: linux-mmc at vger.kernel.org
Cc: linux-nvme at lists.infradead.org
Cc: linux-nfs at vger.kernel.org
Signed-off-by: Guoqing Jiang <guoqing.jiang at cloud.ionos.com>
---
 block/blk-exec.c                   | 10 ++++------
 drivers/block/sx8.c                |  4 ++--
 drivers/nvme/host/core.c           |  4 ++--
 drivers/nvme/host/lightnvm.c       |  2 +-
 drivers/nvme/host/pci.c            |  4 ++--
 drivers/nvme/target/passthru.c     |  2 +-
 drivers/scsi/scsi_error.c          |  2 +-
 drivers/scsi/sg.c                  |  3 +--
 drivers/scsi/st.c                  |  2 +-
 drivers/target/target_core_pscsi.c |  3 +--
 include/linux/blkdev.h             |  2 +-
 11 files changed, 17 insertions(+), 21 deletions(-)

diff --git a/block/blk-exec.c b/block/blk-exec.c
index 85324d53d072..2e37e85456fb 100644
--- a/block/blk-exec.c
+++ b/block/blk-exec.c
@@ -31,8 +31,7 @@ static void blk_end_sync_rq(struct request *rq, blk_status_t error)
 }
 
 /**
- * blk_execute_rq_nowait - insert a request into queue for execution
- * @q:		queue to insert the request in
+ * blk_execute_rq_nowait - insert a request to I/O scheduler for execution
  * @bd_disk:	matching gendisk
  * @rq:		request to insert
  * @at_head:    insert request at head or tail of queue
@@ -45,9 +44,8 @@ static void blk_end_sync_rq(struct request *rq, blk_status_t error)
  * Note:
  *    This function will invoke @done directly if the queue is dead.
  */
-void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
-			   struct request *rq, int at_head,
-			   rq_end_io_fn *done)
+void blk_execute_rq_nowait(struct gendisk *bd_disk, struct request *rq,
+			   int at_head, rq_end_io_fn *done)
 {
 	WARN_ON(irqs_disabled());
 	WARN_ON(!blk_rq_is_passthrough(rq));
@@ -83,7 +81,7 @@ void blk_execute_rq(struct request_queue *q, struct gendisk *bd_disk,
 	unsigned long hang_check;
 
 	rq->end_io_data = &wait;
-	blk_execute_rq_nowait(q, bd_disk, rq, at_head, blk_end_sync_rq);
+	blk_execute_rq_nowait(bd_disk, rq, at_head, blk_end_sync_rq);
 
 	/* Prevent hang_check timer from firing at us during very long I/O */
 	hang_check = sysctl_hung_task_timeout_secs;
diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c
index 4478eb7efee0..2cdf2771f8e8 100644
--- a/drivers/block/sx8.c
+++ b/drivers/block/sx8.c
@@ -539,7 +539,7 @@ static int carm_array_info (struct carm_host *host, unsigned int array_idx)
 	spin_unlock_irq(&host->lock);
 
 	DPRINTK("blk_execute_rq_nowait, tag == %u\n", rq->tag);
-	blk_execute_rq_nowait(host->oob_q, NULL, rq, true, NULL);
+	blk_execute_rq_nowait(NULL, rq, true, NULL);
 
 	return 0;
 
@@ -578,7 +578,7 @@ static int carm_send_special (struct carm_host *host, carm_sspc_t func)
 	crq->msg_bucket = (u32) rc;
 
 	DPRINTK("blk_execute_rq_nowait, tag == %u\n", rq->tag);
-	blk_execute_rq_nowait(host->oob_q, NULL, rq, true, NULL);
+	blk_execute_rq_nowait(NULL, rq, true, NULL);
 
 	return 0;
 }
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index f320273fc672..63c469edb1bc 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -925,7 +925,7 @@ static void nvme_execute_rq_polled(struct request_queue *q,
 
 	rq->cmd_flags |= REQ_HIPRI;
 	rq->end_io_data = &wait;
-	blk_execute_rq_nowait(q, bd_disk, rq, at_head, nvme_end_sync_rq);
+	blk_execute_rq_nowait(bd_disk, rq, at_head, nvme_end_sync_rq);
 
 	while (!completion_done(&wait)) {
 		blk_poll(q, request_to_qc_t(rq->mq_hctx, rq), true);
@@ -1202,7 +1202,7 @@ static int nvme_keep_alive(struct nvme_ctrl *ctrl)
 	rq->timeout = ctrl->kato * HZ;
 	rq->end_io_data = ctrl;
 
-	blk_execute_rq_nowait(rq->q, NULL, rq, 0, nvme_keep_alive_end_io);
+	blk_execute_rq_nowait(NULL, rq, 0, nvme_keep_alive_end_io);
 
 	return 0;
 }
diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index 470cef3abec3..439f2b52e985 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -695,7 +695,7 @@ static int nvme_nvm_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd,
 
 	rq->end_io_data = rqd;
 
-	blk_execute_rq_nowait(q, NULL, rq, 0, nvme_nvm_end_io);
+	blk_execute_rq_nowait(NULL, rq, 0, nvme_nvm_end_io);
 
 	return 0;
 
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 50d9a20568a2..6aa11067c8d0 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -1327,7 +1327,7 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved)
 	}
 
 	abort_req->end_io_data = NULL;
-	blk_execute_rq_nowait(abort_req->q, NULL, abort_req, 0, abort_endio);
+	blk_execute_rq_nowait(NULL, abort_req, 0, abort_endio);
 
 	/*
 	 * The aborted req will be completed on receiving the abort req.
@@ -2238,7 +2238,7 @@ static int nvme_delete_queue(struct nvme_queue *nvmeq, u8 opcode)
 	req->end_io_data = nvmeq;
 
 	init_completion(&nvmeq->delete_done);
-	blk_execute_rq_nowait(q, NULL, req, false,
+	blk_execute_rq_nowait(NULL, req, false,
 			opcode == nvme_admin_delete_cq ?
 				nvme_del_cq_end : nvme_del_queue_end);
 	return 0;
diff --git a/drivers/nvme/target/passthru.c b/drivers/nvme/target/passthru.c
index b9776fc8f08f..cbc88acdd233 100644
--- a/drivers/nvme/target/passthru.c
+++ b/drivers/nvme/target/passthru.c
@@ -275,7 +275,7 @@ static void nvmet_passthru_execute_cmd(struct nvmet_req *req)
 		schedule_work(&req->p.work);
 	} else {
 		rq->end_io_data = req;
-		blk_execute_rq_nowait(rq->q, ns ? ns->disk : NULL, rq, 0,
+		blk_execute_rq_nowait(ns ? ns->disk : NULL, rq, 0,
 				      nvmet_passthru_req_done);
 	}
 
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index f11f51e2465f..c00f06e9ecb0 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -2007,7 +2007,7 @@ static void scsi_eh_lock_door(struct scsi_device *sdev)
 	req->timeout = 10 * HZ;
 	rq->retries = 5;
 
-	blk_execute_rq_nowait(req->q, NULL, req, 1, eh_lock_door_done);
+	blk_execute_rq_nowait(NULL, req, 1, eh_lock_door_done);
 }
 
 /**
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index bfa8d77322d7..4383d93110f8 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -829,8 +829,7 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp,
 
 	srp->rq->timeout = timeout;
 	kref_get(&sfp->f_ref); /* sg_rq_end_io() does kref_put(). */
-	blk_execute_rq_nowait(sdp->device->request_queue, sdp->disk,
-			      srp->rq, at_head, sg_rq_end_io);
+	blk_execute_rq_nowait(sdp->disk, srp->rq, at_head, sg_rq_end_io);
 	return 0;
 }
 
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 43f7624508a9..841ad2fc369a 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -585,7 +585,7 @@ static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd,
 	rq->retries = retries;
 	req->end_io_data = SRpnt;
 
-	blk_execute_rq_nowait(req->q, NULL, req, 1, st_scsi_execute_end);
+	blk_execute_rq_nowait(NULL, req, 1, st_scsi_execute_end);
 	return 0;
 }
 
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c
index 7994f27e4527..33770e5808ce 100644
--- a/drivers/target/target_core_pscsi.c
+++ b/drivers/target/target_core_pscsi.c
@@ -1000,8 +1000,7 @@ pscsi_execute_cmd(struct se_cmd *cmd)
 		req->timeout = PS_TIMEOUT_OTHER;
 	scsi_req(req)->retries = PS_RETRY;
 
-	blk_execute_rq_nowait(pdv->pdv_sd->request_queue, NULL, req,
-			(cmd->sam_task_attr == TCM_HEAD_TAG),
+	blk_execute_rq_nowait(NULL, req, (cmd->sam_task_attr == TCM_HEAD_TAG),
 			pscsi_req_done);
 
 	return 0;
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 070de09425ad..bf0ddef8aa10 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -942,7 +942,7 @@ extern int blk_rq_map_user_iov(struct request_queue *, struct request *,
 			       gfp_t);
 extern void blk_execute_rq(struct request_queue *, struct gendisk *,
 			  struct request *, int);
-extern void blk_execute_rq_nowait(struct request_queue *, struct gendisk *,
+extern void blk_execute_rq_nowait(struct gendisk *,
 				  struct request *, int, rq_end_io_fn *);
 
 /* Helper to convert REQ_OP_XXX to its string format XXX */
-- 
2.17.1



From guoqing.jiang at cloud.ionos.com  Fri Jan 22 04:28:24 2021
From: guoqing.jiang at cloud.ionos.com (Guoqing Jiang)
Date: Fri, 22 Jan 2021 10:28:24 +0100
Subject: [PATCH V2 2/2] block: remove unnecessary argument from blk_execute_rq
In-Reply-To: <20210122092824.20971-1-guoqing.jiang@cloud.ionos.com>
References: <20210122092824.20971-1-guoqing.jiang@cloud.ionos.com>
Message-ID: <20210122092824.20971-3-guoqing.jiang@cloud.ionos.com>

We can remove 'q' from blk_execute_rq as well after the previous change
in blk_execute_rq_nowait.

And more importantly it never really was needed to start with given
that we can trivial derive it from struct request.

Cc: linux-scsi at vger.kernel.org
Cc: virtualization at lists.linux-foundation.org
Cc: linux-ide at vger.kernel.org
Cc: linux-mmc at vger.kernel.org
Cc: linux-nvme at lists.infradead.org
Cc: linux-nfs at vger.kernel.org
Signed-off-by: Guoqing Jiang <guoqing.jiang at cloud.ionos.com>
---
 block/blk-exec.c                  |  3 +--
 block/bsg.c                       |  2 +-
 block/scsi_ioctl.c                |  6 +++---
 drivers/block/mtip32xx/mtip32xx.c |  2 +-
 drivers/block/paride/pd.c         |  2 +-
 drivers/block/pktcdvd.c           |  2 +-
 drivers/block/virtio_blk.c        |  2 +-
 drivers/cdrom/cdrom.c             |  2 +-
 drivers/ide/ide-atapi.c           |  2 +-
 drivers/ide/ide-cd.c              |  2 +-
 drivers/ide/ide-cd_ioctl.c        |  2 +-
 drivers/ide/ide-devsets.c         |  2 +-
 drivers/ide/ide-disk.c            |  2 +-
 drivers/ide/ide-ioctls.c          |  4 ++--
 drivers/ide/ide-park.c            |  2 +-
 drivers/ide/ide-pm.c              |  4 ++--
 drivers/ide/ide-tape.c            |  2 +-
 drivers/ide/ide-taskfile.c        |  2 +-
 drivers/mmc/core/block.c          | 10 +++++-----
 drivers/nvme/host/core.c          |  4 ++--
 drivers/nvme/host/lightnvm.c      |  2 +-
 drivers/scsi/scsi_lib.c           |  2 +-
 fs/nfsd/blocklayout.c             |  2 +-
 include/linux/blkdev.h            |  3 +--
 24 files changed, 33 insertions(+), 35 deletions(-)

diff --git a/block/blk-exec.c b/block/blk-exec.c
index 2e37e85456fb..0ab873f10133 100644
--- a/block/blk-exec.c
+++ b/block/blk-exec.c
@@ -74,8 +74,7 @@ EXPORT_SYMBOL_GPL(blk_execute_rq_nowait);
  *    Insert a fully prepared request at the back of the I/O scheduler queue
  *    for execution and wait for completion.
  */
-void blk_execute_rq(struct request_queue *q, struct gendisk *bd_disk,
-		   struct request *rq, int at_head)
+void blk_execute_rq(struct gendisk *bd_disk, struct request *rq, int at_head)
 {
 	DECLARE_COMPLETION_ONSTACK(wait);
 	unsigned long hang_check;
diff --git a/block/bsg.c b/block/bsg.c
index d7bae94b64d9..26e74a1ad9e2 100644
--- a/block/bsg.c
+++ b/block/bsg.c
@@ -181,7 +181,7 @@ static int bsg_sg_io(struct request_queue *q, fmode_t mode, void __user *uarg)
 
 	bio = rq->bio;
 
-	blk_execute_rq(q, NULL, rq, !(hdr.flags & BSG_FLAG_Q_AT_TAIL));
+	blk_execute_rq(NULL, rq, !(hdr.flags & BSG_FLAG_Q_AT_TAIL));
 	ret = rq->q->bsg_dev.ops->complete_rq(rq, &hdr);
 	blk_rq_unmap_user(bio);
 
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index c9f009cc0446..6599bac0a78c 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -357,7 +357,7 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
 	 * (if he doesn't check that is his problem).
 	 * N.B. a non-zero SCSI status is _not_ necessarily an error.
 	 */
-	blk_execute_rq(q, bd_disk, rq, at_head);
+	blk_execute_rq(bd_disk, rq, at_head);
 
 	hdr->duration = jiffies_to_msecs(jiffies - start_time);
 
@@ -493,7 +493,7 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode,
 		goto error;
 	}
 
-	blk_execute_rq(q, disk, rq, 0);
+	blk_execute_rq(disk, rq, 0);
 
 	err = req->result & 0xff;	/* only 8 bit SCSI status */
 	if (err) {
@@ -532,7 +532,7 @@ static int __blk_send_generic(struct request_queue *q, struct gendisk *bd_disk,
 	scsi_req(rq)->cmd[0] = cmd;
 	scsi_req(rq)->cmd[4] = data;
 	scsi_req(rq)->cmd_len = 6;
-	blk_execute_rq(q, bd_disk, rq, 0);
+	blk_execute_rq(bd_disk, rq, 0);
 	err = scsi_req(rq)->result ? -EIO : 0;
 	blk_put_request(rq);
 
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c
index 53ac59d19ae5..3fd99836bb1c 100644
--- a/drivers/block/mtip32xx/mtip32xx.c
+++ b/drivers/block/mtip32xx/mtip32xx.c
@@ -1015,7 +1015,7 @@ static int mtip_exec_internal_command(struct mtip_port *port,
 	rq->timeout = timeout;
 
 	/* insert request and run queue */
-	blk_execute_rq(rq->q, NULL, rq, true);
+	blk_execute_rq(NULL, rq, true);
 
 	if (int_cmd->status) {
 		dev_err(&dd->pdev->dev, "Internal command [%02X] failed %d\n",
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index a7af4f27b7c3..897acda20ac8 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -781,7 +781,7 @@ static int pd_special_command(struct pd_unit *disk,
 	req = blk_mq_rq_to_pdu(rq);
 
 	req->func = func;
-	blk_execute_rq(disk->gd->queue, disk->gd, rq, 0);
+	blk_execute_rq(disk->gd, rq, 0);
 	blk_put_request(rq);
 	return 0;
 }
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index b8bb8ec7538d..7ce4533a4831 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -722,7 +722,7 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *
 	if (cgc->quiet)
 		rq->rq_flags |= RQF_QUIET;
 
-	blk_execute_rq(rq->q, pd->bdev->bd_disk, rq, 0);
+	blk_execute_rq(pd->bdev->bd_disk, rq, 0);
 	if (scsi_req(rq)->result)
 		ret = -EIO;
 out:
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 145606dc52db..b0285db7cf4f 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -320,7 +320,7 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str)
 	if (err)
 		goto out;
 
-	blk_execute_rq(vblk->disk->queue, vblk->disk, req, false);
+	blk_execute_rq(vblk->disk, req, false);
 	err = blk_status_to_errno(virtblk_result(blk_mq_rq_to_pdu(req)));
 out:
 	blk_put_request(req);
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index 8f0e52a71493..90ad34c6ef8e 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -2214,7 +2214,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
 		rq->timeout = 60 * HZ;
 		bio = rq->bio;
 
-		blk_execute_rq(q, cdi->disk, rq, 0);
+		blk_execute_rq(cdi->disk, rq, 0);
 		if (scsi_req(rq)->result) {
 			struct scsi_sense_hdr sshdr;
 
diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c
index 2162bc80f09e..19aaa8f8aacf 100644
--- a/drivers/ide/ide-atapi.c
+++ b/drivers/ide/ide-atapi.c
@@ -107,7 +107,7 @@ int ide_queue_pc_tail(ide_drive_t *drive, struct gendisk *disk,
 	memcpy(scsi_req(rq)->cmd, pc->c, 12);
 	if (drive->media == ide_tape)
 		scsi_req(rq)->cmd[13] = REQ_IDETAPE_PC1;
-	blk_execute_rq(drive->queue, disk, rq, 0);
+	blk_execute_rq(disk, rq, 0);
 	error = scsi_req(rq)->result ? -EIO : 0;
 put_req:
 	blk_put_request(rq);
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 25d2d88e82ad..cffbcc27a34c 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -467,7 +467,7 @@ int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd,
 			}
 		}
 
-		blk_execute_rq(drive->queue, info->disk, rq, 0);
+		blk_execute_rq(info->disk, rq, 0);
 		error = scsi_req(rq)->result ? -EIO : 0;
 
 		if (buffer)
diff --git a/drivers/ide/ide-cd_ioctl.c b/drivers/ide/ide-cd_ioctl.c
index 46f2df288c6a..011eab9c69b7 100644
--- a/drivers/ide/ide-cd_ioctl.c
+++ b/drivers/ide/ide-cd_ioctl.c
@@ -299,7 +299,7 @@ int ide_cdrom_reset(struct cdrom_device_info *cdi)
 	rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0);
 	ide_req(rq)->type = ATA_PRIV_MISC;
 	rq->rq_flags = RQF_QUIET;
-	blk_execute_rq(drive->queue, cd->disk, rq, 0);
+	blk_execute_rq(cd->disk, rq, 0);
 	ret = scsi_req(rq)->result ? -EIO : 0;
 	blk_put_request(rq);
 	/*
diff --git a/drivers/ide/ide-devsets.c b/drivers/ide/ide-devsets.c
index f2f93ed40356..ca1d4b3d3878 100644
--- a/drivers/ide/ide-devsets.c
+++ b/drivers/ide/ide-devsets.c
@@ -173,7 +173,7 @@ int ide_devset_execute(ide_drive_t *drive, const struct ide_devset *setting,
 	*(int *)&scsi_req(rq)->cmd[1] = arg;
 	ide_req(rq)->special = setting->set;
 
-	blk_execute_rq(q, NULL, rq, 0);
+	blk_execute_rq(NULL, rq, 0);
 	ret = scsi_req(rq)->result;
 	blk_put_request(rq);
 
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index 34b9441084f8..8413731c6259 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -482,7 +482,7 @@ static int set_multcount(ide_drive_t *drive, int arg)
 
 	drive->mult_req = arg;
 	drive->special_flags |= IDE_SFLAG_SET_MULTMODE;
-	blk_execute_rq(drive->queue, NULL, rq, 0);
+	blk_execute_rq(NULL, rq, 0);
 	blk_put_request(rq);
 
 	return (drive->mult_count == arg) ? 0 : -EIO;
diff --git a/drivers/ide/ide-ioctls.c b/drivers/ide/ide-ioctls.c
index 58994da10c06..43fbc37d85c3 100644
--- a/drivers/ide/ide-ioctls.c
+++ b/drivers/ide/ide-ioctls.c
@@ -137,7 +137,7 @@ static int ide_cmd_ioctl(ide_drive_t *drive, void __user *argp)
 
 		rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0);
 		ide_req(rq)->type = ATA_PRIV_TASKFILE;
-		blk_execute_rq(drive->queue, NULL, rq, 0);
+		blk_execute_rq(NULL, rq, 0);
 		err = scsi_req(rq)->result ? -EIO : 0;
 		blk_put_request(rq);
 
@@ -235,7 +235,7 @@ static int generic_drive_reset(ide_drive_t *drive)
 	ide_req(rq)->type = ATA_PRIV_MISC;
 	scsi_req(rq)->cmd_len = 1;
 	scsi_req(rq)->cmd[0] = REQ_DRIVE_RESET;
-	blk_execute_rq(drive->queue, NULL, rq, 1);
+	blk_execute_rq(NULL, rq, 1);
 	ret = scsi_req(rq)->result;
 	blk_put_request(rq);
 	return ret;
diff --git a/drivers/ide/ide-park.c b/drivers/ide/ide-park.c
index 8af7af6001eb..a80a0f28f7b9 100644
--- a/drivers/ide/ide-park.c
+++ b/drivers/ide/ide-park.c
@@ -37,7 +37,7 @@ static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout)
 	scsi_req(rq)->cmd_len = 1;
 	ide_req(rq)->type = ATA_PRIV_MISC;
 	ide_req(rq)->special = &timeout;
-	blk_execute_rq(q, NULL, rq, 1);
+	blk_execute_rq(NULL, rq, 1);
 	rc = scsi_req(rq)->result ? -EIO : 0;
 	blk_put_request(rq);
 	if (rc)
diff --git a/drivers/ide/ide-pm.c b/drivers/ide/ide-pm.c
index 192e6c65d34e..fc3cb37fec14 100644
--- a/drivers/ide/ide-pm.c
+++ b/drivers/ide/ide-pm.c
@@ -27,7 +27,7 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg)
 		mesg.event = PM_EVENT_FREEZE;
 	rqpm.pm_state = mesg.event;
 
-	blk_execute_rq(drive->queue, NULL, rq, 0);
+	blk_execute_rq(NULL, rq, 0);
 	ret = scsi_req(rq)->result ? -EIO : 0;
 	blk_put_request(rq);
 
@@ -50,7 +50,7 @@ static int ide_pm_execute_rq(struct request *rq)
 		blk_mq_end_request(rq, BLK_STS_OK);
 		return -ENXIO;
 	}
-	blk_execute_rq(q, NULL, rq, true);
+	blk_execute_rq(NULL, rq, true);
 
 	return scsi_req(rq)->result ? -EIO : 0;
 }
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index 88b96437b22e..fa05e7e7d609 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -868,7 +868,7 @@ static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int size)
 			goto out_put;
 	}
 
-	blk_execute_rq(drive->queue, tape->disk, rq, 0);
+	blk_execute_rq(tape->disk, rq, 0);
 
 	/* calculate the number of transferred bytes and update buffer state */
 	size -= scsi_req(rq)->resid_len;
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index d016cbe68cba..6665fc4724b9 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -443,7 +443,7 @@ int ide_raw_taskfile(ide_drive_t *drive, struct ide_cmd *cmd, u8 *buf,
 	ide_req(rq)->special = cmd;
 	cmd->rq = rq;
 
-	blk_execute_rq(drive->queue, NULL, rq, 0);
+	blk_execute_rq(NULL, rq, 0);
 	error = scsi_req(rq)->result ? -EIO : 0;
 put_req:
 	blk_put_request(rq);
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index 42e27a298218..a1d6b68320ae 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -253,7 +253,7 @@ static ssize_t power_ro_lock_store(struct device *dev,
 		goto out_put;
 	}
 	req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_BOOT_WP;
-	blk_execute_rq(mq->queue, NULL, req, 0);
+	blk_execute_rq(NULL, req, 0);
 	ret = req_to_mmc_queue_req(req)->drv_op_result;
 	blk_put_request(req);
 
@@ -629,7 +629,7 @@ static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md,
 		rpmb ? MMC_DRV_OP_IOCTL_RPMB : MMC_DRV_OP_IOCTL;
 	req_to_mmc_queue_req(req)->drv_op_data = idatas;
 	req_to_mmc_queue_req(req)->ioc_count = 1;
-	blk_execute_rq(mq->queue, NULL, req, 0);
+	blk_execute_rq(NULL, req, 0);
 	ioc_err = req_to_mmc_queue_req(req)->drv_op_result;
 	err = mmc_blk_ioctl_copy_to_user(ic_ptr, idata);
 	blk_put_request(req);
@@ -698,7 +698,7 @@ static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md,
 		rpmb ? MMC_DRV_OP_IOCTL_RPMB : MMC_DRV_OP_IOCTL;
 	req_to_mmc_queue_req(req)->drv_op_data = idata;
 	req_to_mmc_queue_req(req)->ioc_count = num_of_cmds;
-	blk_execute_rq(mq->queue, NULL, req, 0);
+	blk_execute_rq(NULL, req, 0);
 	ioc_err = req_to_mmc_queue_req(req)->drv_op_result;
 
 	/* copy to user if data and response */
@@ -2722,7 +2722,7 @@ static int mmc_dbg_card_status_get(void *data, u64 *val)
 	if (IS_ERR(req))
 		return PTR_ERR(req);
 	req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_GET_CARD_STATUS;
-	blk_execute_rq(mq->queue, NULL, req, 0);
+	blk_execute_rq(NULL, req, 0);
 	ret = req_to_mmc_queue_req(req)->drv_op_result;
 	if (ret >= 0) {
 		*val = ret;
@@ -2761,7 +2761,7 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp)
 	}
 	req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_GET_EXT_CSD;
 	req_to_mmc_queue_req(req)->drv_op_data = &ext_csd;
-	blk_execute_rq(mq->queue, NULL, req, 0);
+	blk_execute_rq(NULL, req, 0);
 	err = req_to_mmc_queue_req(req)->drv_op_result;
 	blk_put_request(req);
 	if (err) {
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 63c469edb1bc..d3d6e950dda2 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -964,7 +964,7 @@ int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
 	if (poll)
 		nvme_execute_rq_polled(req->q, NULL, req, at_head);
 	else
-		blk_execute_rq(req->q, NULL, req, at_head);
+		blk_execute_rq(NULL, req, at_head);
 	if (result)
 		*result = nvme_req(req)->result;
 	if (nvme_req(req)->flags & NVME_REQ_CANCELLED)
@@ -1101,7 +1101,7 @@ void nvme_execute_passthru_rq(struct request *rq)
 	u32 effects;
 
 	effects = nvme_passthru_start(ctrl, ns, cmd->common.opcode);
-	blk_execute_rq(rq->q, disk, rq, 0);
+	blk_execute_rq(disk, rq, 0);
 	nvme_passthru_end(ctrl, effects);
 }
 EXPORT_SYMBOL_NS_GPL(nvme_execute_passthru_rq, NVME_TARGET_PASSTHRU);
diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index 439f2b52e985..e0443755884b 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -820,7 +820,7 @@ static int nvme_nvm_submit_user_cmd(struct request_queue *q,
 		bio->bi_disk = disk;
 	}
 
-	blk_execute_rq(q, NULL, rq, 0);
+	blk_execute_rq(NULL, rq, 0);
 
 	if (nvme_req(rq)->flags & NVME_REQ_CANCELLED)
 		ret = -EINTR;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 4848ae3c7b56..475e40c9493f 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -268,7 +268,7 @@ int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
 	/*
 	 * head injection *required* here otherwise quiesce won't work
 	 */
-	blk_execute_rq(req->q, NULL, req, 1);
+	blk_execute_rq(NULL, req, 1);
 
 	/*
 	 * Some devices (USB mass-storage in particular) may transfer
diff --git a/fs/nfsd/blocklayout.c b/fs/nfsd/blocklayout.c
index a07c39c94bbd..1058659a8d31 100644
--- a/fs/nfsd/blocklayout.c
+++ b/fs/nfsd/blocklayout.c
@@ -254,7 +254,7 @@ static int nfsd4_scsi_identify_device(struct block_device *bdev,
 	req->cmd[4] = bufflen & 0xff;
 	req->cmd_len = COMMAND_SIZE(INQUIRY);
 
-	blk_execute_rq(rq->q, NULL, rq, 1);
+	blk_execute_rq(NULL, rq, 1);
 	if (req->result) {
 		pr_err("pNFS: INQUIRY 0x83 failed with: %x\n",
 			req->result);
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index bf0ddef8aa10..09caa1de28b0 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -940,8 +940,7 @@ extern int blk_rq_map_kern(struct request_queue *, struct request *, void *, uns
 extern int blk_rq_map_user_iov(struct request_queue *, struct request *,
 			       struct rq_map_data *, const struct iov_iter *,
 			       gfp_t);
-extern void blk_execute_rq(struct request_queue *, struct gendisk *,
-			  struct request *, int);
+extern void blk_execute_rq(struct gendisk *, struct request *, int);
 extern void blk_execute_rq_nowait(struct gendisk *,
 				  struct request *, int, rq_end_io_fn *);
 
-- 
2.17.1



From ulf.hansson at linaro.org  Fri Jan 22 04:50:20 2021
From: ulf.hansson at linaro.org (Ulf Hansson)
Date: Fri, 22 Jan 2021 10:50:20 +0100
Subject: [PATCH V2 2/2] block: remove unnecessary argument from
 blk_execute_rq
In-Reply-To: <20210122092824.20971-3-guoqing.jiang@cloud.ionos.com>
References: <20210122092824.20971-1-guoqing.jiang@cloud.ionos.com>
 <20210122092824.20971-3-guoqing.jiang@cloud.ionos.com>
Message-ID: <CAPDyKFoPL4drfh3efKXyhXLp6Ce+j=oHwNd9VnVP4aaKQ0zmDQ@mail.gmail.com>

On Fri, 22 Jan 2021 at 10:28, Guoqing Jiang
<guoqing.jiang at cloud.ionos.com> wrote:
>
> We can remove 'q' from blk_execute_rq as well after the previous change
> in blk_execute_rq_nowait.
>
> And more importantly it never really was needed to start with given
> that we can trivial derive it from struct request.
>
> Cc: linux-scsi at vger.kernel.org
> Cc: virtualization at lists.linux-foundation.org
> Cc: linux-ide at vger.kernel.org
> Cc: linux-mmc at vger.kernel.org
> Cc: linux-nvme at lists.infradead.org
> Cc: linux-nfs at vger.kernel.org
> Signed-off-by: Guoqing Jiang <guoqing.jiang at cloud.ionos.com>

[...]

>  drivers/mmc/core/block.c          | 10 +++++-----

[...]

>From mmc point of view, please add:

Acked-by: Ulf Hansson <ulf.hansson at linaro.org>

At the moment I don't think this will conflict with any changes to
mmc, but if that happens let's sort it then...

Kind regards
Uffe


From hare at suse.de  Fri Jan 22 11:35:35 2021
From: hare at suse.de (Hannes Reinecke)
Date: Fri, 22 Jan 2021 17:35:35 +0100
Subject: [PATCH] nvme: do not ignore nvme status in nvme_set_queue_count()
In-Reply-To: <20210121201459.GA1727271@dhcp-10-100-145-180.wdc.com>
References: <20210121095021.22807-1-hare@suse.de>
 <20210121201459.GA1727271@dhcp-10-100-145-180.wdc.com>
Message-ID: <f374b032-cd26-4552-b613-228449f4971d@suse.de>

On 1/21/21 9:14 PM, Keith Busch wrote:
> On Thu, Jan 21, 2021 at 10:50:21AM +0100, Hannes Reinecke wrote:
>> If the call to nvme_set_queue_count() fails with a status we should
>> not ignore it but rather pass it on to the caller.
>> It's then up to the transport to decide whether to ignore it
>> (like PCI does) or to reset the connection (as would be appropriate
>> for fabrics).
> 
> Instead of checking the error, wouldn't checking the number of created
> queues be sufficient? What handling difference do you expect to occur
> between getting a success with 0 queues, vs getting an error?
> 
The difference is that an error will (re-)start recovery, 0 queues won't.
But the problem here is that nvme_set_queue_count() is being called 
during reconnection, ie during the recovery process itself.
And this command is returned with a timeout, which in any other case is 
being treated as a fatal error. Plus we have been sending this command 
on the admin queue, so a timeout on the admin queue pretty much _is_  a 
fatal error. So we should be terminating the current recovery and 
reconnect. None of that will happen if we return '0' queues.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare at suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 N?rnberg
HRB 36809 (AG N?rnberg), Gesch?ftsf?hrer: Felix Imend?rffer


From kbusch at kernel.org  Fri Jan 22 11:44:54 2021
From: kbusch at kernel.org (Keith Busch)
Date: Sat, 23 Jan 2021 01:44:54 +0900
Subject: [PATCH] nvme: do not ignore nvme status in nvme_set_queue_count()
In-Reply-To: <f374b032-cd26-4552-b613-228449f4971d@suse.de>
References: <20210121095021.22807-1-hare@suse.de>
 <20210121201459.GA1727271@dhcp-10-100-145-180.wdc.com>
 <f374b032-cd26-4552-b613-228449f4971d@suse.de>
Message-ID: <20210122164454.GA4392@redsun51.ssa.fujisawa.hgst.com>

On Fri, Jan 22, 2021 at 05:35:35PM +0100, Hannes Reinecke wrote:
> On 1/21/21 9:14 PM, Keith Busch wrote:
> > On Thu, Jan 21, 2021 at 10:50:21AM +0100, Hannes Reinecke wrote:
> > > If the call to nvme_set_queue_count() fails with a status we should
> > > not ignore it but rather pass it on to the caller.
> > > It's then up to the transport to decide whether to ignore it
> > > (like PCI does) or to reset the connection (as would be appropriate
> > > for fabrics).
> > 
> > Instead of checking the error, wouldn't checking the number of created
> > queues be sufficient? What handling difference do you expect to occur
> > between getting a success with 0 queues, vs getting an error?
> > 
> The difference is that an error will (re-)start recovery, 0 queues won't.
> But the problem here is that nvme_set_queue_count() is being called during
> reconnection, ie during the recovery process itself.
> And this command is returned with a timeout, which in any other case is
> being treated as a fatal error. Plus we have been sending this command on
> the admin queue, so a timeout on the admin queue pretty much _is_  a fatal
> error. So we should be terminating the current recovery and reconnect. None
> of that will happen if we return '0' queues.

You should already be getting an error return status if a timeout occurs
for nvme_set_queue_count(), specifically -EINTR. Are you getting success
for some reason?


From dwagner at suse.de  Fri Jan 22 12:41:25 2021
From: dwagner at suse.de (Daniel Wagner)
Date: Fri, 22 Jan 2021 18:41:25 +0100
Subject: [PATCH] nvme-multipath: Early exit if no path is available
Message-ID: <20210122174125.145734-1-dwagner@suse.de>

nvme_round_robin_path() should test if the return ns pointer is
valid. nvme_next_ns() will return a NULL pointer if there is no path
left.

Signed-off-by: Daniel Wagner <dwagner at suse.de>
---
 drivers/nvme/host/multipath.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
index d578de0ce3aa..8837e9da1ccf 100644
--- a/drivers/nvme/host/multipath.c
+++ b/drivers/nvme/host/multipath.c
@@ -239,6 +239,8 @@ static struct nvme_ns *nvme_round_robin_path(struct nvme_ns_head *head,
 	for (ns = nvme_next_ns(head, old);
 	     ns != old;
 	     ns = nvme_next_ns(head, ns)) {
+		if (!ns)
+			break;
 		if (nvme_path_is_disabled(ns))
 			continue;
 
-- 
2.29.2



From hch at lst.de  Fri Jan 22 12:50:29 2021
From: hch at lst.de (Christoph Hellwig)
Date: Fri, 22 Jan 2021 18:50:29 +0100
Subject: [PATCH] nvme-multipath: Early exit if no path is available
In-Reply-To: <20210122174125.145734-1-dwagner@suse.de>
References: <20210122174125.145734-1-dwagner@suse.de>
Message-ID: <20210122175029.GA21127@lst.de>

On Fri, Jan 22, 2021 at 06:41:25PM +0100, Daniel Wagner wrote:
> nvme_round_robin_path() should test if the return ns pointer is
> valid. nvme_next_ns() will return a NULL pointer if there is no path
> left.

How can that happen once we're in the loop?


From dwagner at suse.de  Fri Jan 22 12:55:08 2021
From: dwagner at suse.de (Daniel Wagner)
Date: Fri, 22 Jan 2021 18:55:08 +0100
Subject: [PATCH] nvme-multipath: Early exit if no path is available
In-Reply-To: <20210122175029.GA21127@lst.de>
References: <20210122174125.145734-1-dwagner@suse.de>
 <20210122175029.GA21127@lst.de>
Message-ID: <20210122175508.eiimz2fbx3csrejk@beryllium.lan>

On Fri, Jan 22, 2021 at 06:50:29PM +0100, Christoph Hellwig wrote:
> How can that happen once we're in the loop?

As far I can tell, it's the first nvme_next_ns() call which returns the
NULL pointer and this will pass the test 'ns != old'.


From yogi43222 at gmail.com  Fri Jan 22 13:53:39 2021
From: yogi43222 at gmail.com (Yogi Wannabe)
Date: Fri, 22 Jan 2021 10:53:39 -0800
Subject: Peer to peer DMA
Message-ID: <CAGSHeY1TRkrcpnYYJhkuD9A1Qvn9vDYQh5yC=y+6x4wj5_RqKA@mail.gmail.com>

Hi all,

is it possible to DMA between two NVME SSD drives plugged into a
system with Intel Xeon? If it is possible, how does one do it?

thanks for your help
Yogi


From chapman6235 at comcast.net  Fri Jan 22 19:54:26 2021
From: chapman6235 at comcast.net (Bradley Chapman)
Date: Fri, 22 Jan 2021 19:54:26 -0500
Subject: Problem with SPCC 256GB NVMe 1.3 drive - refcount_t: underflow;
 use-after-free.
In-Reply-To: <BYAPR04MB4965342B52D5C3C6D8A7892D86A00@BYAPR04MB4965.namprd04.prod.outlook.com>
References: <f50bc59c-db11-bb44-55be-7b9db1119872@comcast.net>
 <BYAPR04MB49659C0F0F0E11D166B31E0586A40@BYAPR04MB4965.namprd04.prod.outlook.com>
 <a4c75497-d170-1e0f-8608-282231ff3a8e@comcast.net>
 <BYAPR04MB496542BEF594F0380F7D41CF86A20@BYAPR04MB4965.namprd04.prod.outlook.com>
 <df46d7ce-ce70-1f43-0efd-7153761bcff0@comcast.net>
 <20210121124459.GA156577@localhost.localdomain>
 <c48abecf-8e4f-b76a-c751-1a0d239c99b3@comcast.net>
 <BYAPR04MB4965404638B4C43DBA577D1686A00@BYAPR04MB4965.namprd04.prod.outlook.com>
 <BYAPR04MB4965342B52D5C3C6D8A7892D86A00@BYAPR04MB4965.namprd04.prod.outlook.com>
Message-ID: <23f49172-5d0e-618a-199d-d568f695dc30@comcast.net>

Hello sir!

I didn't check my e-mail until this evening, so I saw all four of your 
e-mails at once. I ran the commands you specified based on the following 
information from dmesg and lspci:

dmesg:
[    1.633908] nvme nvme1: pci function 0000:04:00.0

lspci:
04:00.0 Non-Volatile memory controller: Device 1d97:2263 (rev 03)

$ cat /sys/bus/pci/devices/0000\:04\:00.0/device
0x2263

$ cat /sys/bus/pci/devices/0000\:04\:00.0/vendor
0x1d97

On 1/21/21 10:16 PM, Chaitanya Kulkarni wrote:
> On 1/21/21 6:57 PM, Chaitanya Kulkarni wrote:
>> Bradley,
>>
>> On 1/21/21 6:54 PM, Bradley Chapman wrote:
>>> I compiled the kernel from the above git tree, rebooted and attempted to
>>> mount the filesystem on the NVMe drive. This is what the kernel put into
>>> the dmesg when I attempted to list the contents of the filesystem root,
>>> create an inode for a zero-byte file and then unmount the filesystem.
>>>
>>> Brad
>> Did you get a chance to see my response to your previous email ?
>>
> You can try following patch with some modification :-
> 
>>From e162a2e91e4895ceac6f80042a87c4ba6a4fbbf5 Mon Sep 17 00:00:00 2001
> From: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
> Date: Thu, 21 Jan 2021 19:05:13 -0800
> Subject: [PATCH] nvme-pci: add device quirk wip
> 
> This is work in progress patch which is based on nvme-5.12
> HEAD : b116d37fc0f5 nvmet: add lba to sect conversion helpers
> 
> Replace <YOUR DEVICE'S VENDOR ID> and <YOUR DEVICE's DEVICE ID> with
> actual values sysfs entries in patch below before you apply the patch :-
> 
> cat  /sys/bus/pci/devices/<your device id>/device
> cat  /sys/bus/pci/devices/<your device id>/vendor
> 
> This patch is not tested at all.
> 
> Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
> ---
>   drivers/nvme/host/pci.c | 2 ++
>   1 file changed, 2 insertions(+)
> 
> diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
> index 25456d02eddb..c5b43bcf57b0 100644
> --- a/drivers/nvme/host/pci.c
> +++ b/drivers/nvme/host/pci.c
> @@ -3228,6 +3228,8 @@ static const struct pci_device_id nvme_id_table[] = {
>           .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
>       { PCI_DEVICE(0x15b7, 0x2001),   /*  Sandisk Skyhawk */
>           .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
> +    { PCI_DEVICE(<YOUR DEVICE's VENDOR ID>, <YOUR DEVICE's DEVICE ID>),
> +        .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
>       { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2001),
>           .driver_data = NVME_QUIRK_SINGLE_VECTOR },
>       { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2003) },
> 

With the following patch applied to the NVMe tree, my system hard-locked 
and would not respond to Alt+SysRQ once I mounted the filesystem and 
attempted a directory listing of the root of the filesystem.

diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 25456d02eddb..7ba5e8e92e19 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -3228,6 +3228,8 @@ static const struct pci_device_id nvme_id_table[] = {
                 .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
         { PCI_DEVICE(0x15b7, 0x2001),   /*  Sandisk Skyhawk */
                 .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
+       { PCI_DEVICE(0x1d97, 0x2263),   /*  SPCC */
+               .driver_data = NVME_QUIRK_SINGLE_VECTOR },
         { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2001),
                 .driver_data = NVME_QUIRK_SINGLE_VECTOR },
         { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2003) },

I don't have a serial console, nor a serial port or other suitable 
cabling to make one, so I have no console logs of what caused the hard 
lockup, and the lack of response to Alt+SysRQ+S meant that I have no 
written logs to share with you all. I'm a bit leery of hard-locking the 
system multiple times to try to snipe the dmesg, since I don't want to 
trash the other filesystems on this host. What else can I try before I 
do that?

Brad


From martin.petersen at oracle.com  Fri Jan 22 21:43:02 2021
From: martin.petersen at oracle.com (Martin K. Petersen)
Date: Fri, 22 Jan 2021 21:43:02 -0500
Subject: [PATCH v3 1/3] block: introduce zone_write_granularity limit
In-Reply-To: <20210122080014.174391-2-damien.lemoal@wdc.com> (Damien Le Moal's
 message of "Fri, 22 Jan 2021 17:00:12 +0900")
References: <20210122080014.174391-1-damien.lemoal@wdc.com>
 <20210122080014.174391-2-damien.lemoal@wdc.com>
Message-ID: <yq1sg6sbche.fsf@ca-mkp.ca.oracle.com>


Damien,

> To solve this, introduce the zone_write_granularity queue limit to
> indicate the alignment constraint, in bytes, of write operations into
> zones of a zoned block device. This new limit is exported as a
> read-only sysfs queue attribute and the helper
> blk_queue_zone_write_granularity() introduced for drivers to set this
> limit. The scsi disk driver is modified to use this helper to set
> host-managed SMR disk zone write granularity to the disk physical
> block size. The ZNS support code of the NVMe driver is also modified
> to use this helper to set the new limit to the logical block size of
> the namespace. The nullblk driver is similarly modified too.

Looks fine.

Reviewed-by: Martin K. Petersen <martin.petersen at oracle.com>

-- 
Martin K. Petersen	Oracle Linux Engineering


From martin.petersen at oracle.com  Fri Jan 22 21:43:28 2021
From: martin.petersen at oracle.com (Martin K. Petersen)
Date: Fri, 22 Jan 2021 21:43:28 -0500
Subject: [PATCH v3 2/3] block: document zone_append_max_bytes attribute
In-Reply-To: <20210122080014.174391-3-damien.lemoal@wdc.com> (Damien Le Moal's
 message of "Fri, 22 Jan 2021 17:00:13 +0900")
References: <20210122080014.174391-1-damien.lemoal@wdc.com>
 <20210122080014.174391-3-damien.lemoal@wdc.com>
Message-ID: <yq1mtx0bcfs.fsf@ca-mkp.ca.oracle.com>


Damien,

> The description of the zone_append_max_bytes sysfs queue attribute is
> missing from Documentation/block/queue-sysfs.rst. Add it.

Reviewed-by: Martin K. Petersen <martin.petersen at oracle.com>

-- 
Martin K. Petersen	Oracle Linux Engineering


From martin.petersen at oracle.com  Fri Jan 22 21:44:00 2021
From: martin.petersen at oracle.com (Martin K. Petersen)
Date: Fri, 22 Jan 2021 21:44:00 -0500
Subject: [PATCH v3 3/3] zonefs: use zone write granularity as block size
In-Reply-To: <20210122080014.174391-4-damien.lemoal@wdc.com> (Damien Le Moal's
 message of "Fri, 22 Jan 2021 17:00:14 +0900")
References: <20210122080014.174391-1-damien.lemoal@wdc.com>
 <20210122080014.174391-4-damien.lemoal@wdc.com>
Message-ID: <yq1h7n8bcey.fsf@ca-mkp.ca.oracle.com>


Damien,

> Zoned block devices have different granularity constraints for write
> operations into sequential zones. E.g. ZBC and ZAC devices require
> that writes be aligned to the device physical block size while NVMe
> ZNS devices allow logical block size aligned write operations. To
> correctly handle such difference, use the device zone write
> granularity limit to set the block size of a zonefs volume, thus
> allowing the smallest possible write unit for all zoned device types.

Reviewed-by: Martin K. Petersen <martin.petersen at oracle.com>

-- 
Martin K. Petersen	Oracle Linux Engineering


From Chaitanya.Kulkarni at wdc.com  Fri Jan 22 22:03:25 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Sat, 23 Jan 2021 03:03:25 +0000
Subject: [PATCH v3 2/3] block: document zone_append_max_bytes attribute
References: <20210122080014.174391-1-damien.lemoal@wdc.com>
 <20210122080014.174391-3-damien.lemoal@wdc.com>
Message-ID: <DM6PR04MB49728F70DE83642A3B61D51E86BF0@DM6PR04MB4972.namprd04.prod.outlook.com>

On 1/22/21 12:00 AM, Damien Le Moal wrote:
> The description of the zone_append_max_bytes sysfs queue attribute is
> missing from Documentation/block/queue-sysfs.rst. Add it.
>
> Signed-off-by: Damien Le Moal <damien.lemoal at wdc.com>
> Reviewed-by: Christoph Hellwig <hch at lst.de>
Looks good.

Reviewed-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>


From hch at lst.de  Sun Jan 24 05:07:24 2021
From: hch at lst.de (Christoph Hellwig)
Date: Sun, 24 Jan 2021 11:07:24 +0100
Subject: [PATCH v3 1/3] block: introduce zone_write_granularity limit
In-Reply-To: <BL0PR04MB6514A2655635DFF482E4252BE7A00@BL0PR04MB6514.namprd04.prod.outlook.com>
References: <20210122080014.174391-1-damien.lemoal@wdc.com>
 <20210122080014.174391-2-damien.lemoal@wdc.com>
 <20210122084209.GA15710@lst.de>
 <BL0PR04MB6514A2655635DFF482E4252BE7A00@BL0PR04MB6514.namprd04.prod.outlook.com>
Message-ID: <20210124100724.GA27580@lst.de>

On Fri, Jan 22, 2021 at 08:56:58AM +0000, Damien Le Moal wrote:
> > This looks a little strange.  If we special case zoned vs not zoned
> > here anyway, why not set the zone_write_granularity to the logical
> > block size here by default.
> 
> The convention is zone_write_granularity == 0 for the BLK_ZONED_NONE case. Hence
> the reset here if we force the zoned model to none for HA drives. This way, this
> does not create a special case for HA drives used as regular disks.

Just inititialize it for all cases if you initialize it for some here.
That way everyone but sd already gets a right default and life becomes
simpler.


From axboe at kernel.dk  Sun Jan 24 20:24:07 2021
From: axboe at kernel.dk (Jens Axboe)
Date: Sun, 24 Jan 2021 18:24:07 -0700
Subject: [PATCH V2 0/2] remove unused argument from blk_execute_rq_nowait
 and blk_execute_rq
In-Reply-To: <20210122092824.20971-1-guoqing.jiang@cloud.ionos.com>
References: <20210122092824.20971-1-guoqing.jiang@cloud.ionos.com>
Message-ID: <683e16be-1146-e60c-cfea-e4606844f080@kernel.dk>

On 1/22/21 2:28 AM, Guoqing Jiang wrote:
> V2 changes:
> 1. update commit header per Christoph's comment.
> 
> Hi Jens,
> 
> This series remove unused 'q' from blk_execute_rq_nowait and blk_execute_rq.
> Also update the comment for blk_execute_rq_nowait.

What's this against? The lightnvm patch doesn't apply.

-- 
Jens Axboe



From guoqing.jiang at cloud.ionos.com  Sun Jan 24 23:34:52 2021
From: guoqing.jiang at cloud.ionos.com (Guoqing Jiang)
Date: Mon, 25 Jan 2021 05:34:52 +0100
Subject: [PATCH V2 0/2] remove unused argument from blk_execute_rq_nowait
 and blk_execute_rq
In-Reply-To: <683e16be-1146-e60c-cfea-e4606844f080@kernel.dk>
References: <20210122092824.20971-1-guoqing.jiang@cloud.ionos.com>
 <683e16be-1146-e60c-cfea-e4606844f080@kernel.dk>
Message-ID: <73fd70be-90bc-9c6c-dcbe-7981f8fef4f5@cloud.ionos.com>



On 1/25/21 02:24, Jens Axboe wrote:
> On 1/22/21 2:28 AM, Guoqing Jiang wrote:
>> V2 changes:
>> 1. update commit header per Christoph's comment.
>>
>> Hi Jens,
>>
>> This series remove unused 'q' from blk_execute_rq_nowait and blk_execute_rq.
>> Also update the comment for blk_execute_rq_nowait.
> 
> What's this against? The lightnvm patch doesn't apply.
> 

Sorry for that, will resend against for-5.12/block.

Thanks,
Guoqing


From guoqing.jiang at cloud.ionos.com  Sun Jan 24 23:35:54 2021
From: guoqing.jiang at cloud.ionos.com (Guoqing Jiang)
Date: Mon, 25 Jan 2021 05:35:54 +0100
Subject: [PATCH V2 2/2] block: remove unnecessary argument from
 blk_execute_rq
In-Reply-To: <CAPDyKFoPL4drfh3efKXyhXLp6Ce+j=oHwNd9VnVP4aaKQ0zmDQ@mail.gmail.com>
References: <20210122092824.20971-1-guoqing.jiang@cloud.ionos.com>
 <20210122092824.20971-3-guoqing.jiang@cloud.ionos.com>
 <CAPDyKFoPL4drfh3efKXyhXLp6Ce+j=oHwNd9VnVP4aaKQ0zmDQ@mail.gmail.com>
Message-ID: <439d415f-6aed-7092-a593-0d2d490652d2@cloud.ionos.com>



On 1/22/21 10:50, Ulf Hansson wrote:
> On Fri, 22 Jan 2021 at 10:28, Guoqing Jiang
> <guoqing.jiang at cloud.ionos.com> wrote:
>>
>> We can remove 'q' from blk_execute_rq as well after the previous change
>> in blk_execute_rq_nowait.
>>
>> And more importantly it never really was needed to start with given
>> that we can trivial derive it from struct request.
>>
>> Cc: linux-scsi at vger.kernel.org
>> Cc: virtualization at lists.linux-foundation.org
>> Cc: linux-ide at vger.kernel.org
>> Cc: linux-mmc at vger.kernel.org
>> Cc: linux-nvme at lists.infradead.org
>> Cc: linux-nfs at vger.kernel.org
>> Signed-off-by: Guoqing Jiang <guoqing.jiang at cloud.ionos.com>
> 
> [...]
> 
>>   drivers/mmc/core/block.c          | 10 +++++-----
> 
> [...]
> 
>  From mmc point of view, please add:
> 
> Acked-by: Ulf Hansson <ulf.hansson at linaro.org>
> 
> At the moment I don't think this will conflict with any changes to
> mmc, but if that happens let's sort it then...
> 

Thank you! Will resend and add your acked-by.

Guoqing


From guoqing.jiang at cloud.ionos.com  Sun Jan 24 23:49:56 2021
From: guoqing.jiang at cloud.ionos.com (Guoqing Jiang)
Date: Mon, 25 Jan 2021 05:49:56 +0100
Subject: [PATCH V3 0/2] remove unused argument from blk_execute_rq_nowait and
 blk_execute_rq
Message-ID: <1611550198-17142-1-git-send-email-guoqing.jiang@cloud.ionos.com>

V3 changes:
1. rebase with for-5.12/block branch.
2. add Ulf's Acked-by.

V2 changes:
1. update commit header per Christoph's comment.

Hi Jens,

This series remove unused 'q' from blk_execute_rq_nowait and blk_execute_rq.
Also update the comment for blk_execute_rq_nowait.

Thanks,
Guoqing

Guoqing Jiang (2):
  block: remove unnecessary argument from blk_execute_rq_nowait
  block: remove unnecessary argument from blk_execute_rq

 block/blk-exec.c                   | 13 +++++--------
 block/bsg.c                        |  2 +-
 block/scsi_ioctl.c                 |  6 +++---
 drivers/block/mtip32xx/mtip32xx.c  |  2 +-
 drivers/block/paride/pd.c          |  2 +-
 drivers/block/pktcdvd.c            |  2 +-
 drivers/block/sx8.c                |  4 ++--
 drivers/block/virtio_blk.c         |  2 +-
 drivers/cdrom/cdrom.c              |  2 +-
 drivers/ide/ide-atapi.c            |  2 +-
 drivers/ide/ide-cd.c               |  2 +-
 drivers/ide/ide-cd_ioctl.c         |  2 +-
 drivers/ide/ide-devsets.c          |  2 +-
 drivers/ide/ide-disk.c             |  2 +-
 drivers/ide/ide-ioctls.c           |  4 ++--
 drivers/ide/ide-park.c             |  2 +-
 drivers/ide/ide-pm.c               |  4 ++--
 drivers/ide/ide-tape.c             |  2 +-
 drivers/ide/ide-taskfile.c         |  2 +-
 drivers/mmc/core/block.c           | 10 +++++-----
 drivers/nvme/host/core.c           |  8 ++++----
 drivers/nvme/host/lightnvm.c       |  4 ++--
 drivers/nvme/host/pci.c            |  4 ++--
 drivers/nvme/target/passthru.c     |  2 +-
 drivers/scsi/scsi_error.c          |  2 +-
 drivers/scsi/scsi_lib.c            |  2 +-
 drivers/scsi/sg.c                  |  3 +--
 drivers/scsi/st.c                  |  2 +-
 drivers/target/target_core_pscsi.c |  3 +--
 fs/nfsd/blocklayout.c              |  2 +-
 include/linux/blkdev.h             |  5 ++---
 31 files changed, 50 insertions(+), 56 deletions(-)

-- 
2.7.4



From guoqing.jiang at cloud.ionos.com  Sun Jan 24 23:49:57 2021
From: guoqing.jiang at cloud.ionos.com (Guoqing Jiang)
Date: Mon, 25 Jan 2021 05:49:57 +0100
Subject: [PATCH V3 1/2] block: remove unnecessary argument from
 blk_execute_rq_nowait
In-Reply-To: <1611550198-17142-1-git-send-email-guoqing.jiang@cloud.ionos.com>
References: <1611550198-17142-1-git-send-email-guoqing.jiang@cloud.ionos.com>
Message-ID: <1611550198-17142-2-git-send-email-guoqing.jiang@cloud.ionos.com>

The 'q' is not used since commit a1ce35fa4985 ("block: remove dead
elevator code"), also update the comment of the function.

And more importantly it never really was needed to start with given
that we can trivial derive it from struct request.

Cc: target-devel at vger.kernel.org
Cc: linux-scsi at vger.kernel.org
Cc: virtualization at lists.linux-foundation.org
Cc: linux-ide at vger.kernel.org
Cc: linux-mmc at vger.kernel.org
Cc: linux-nvme at lists.infradead.org
Cc: linux-nfs at vger.kernel.org
Signed-off-by: Guoqing Jiang <guoqing.jiang at cloud.ionos.com>
---
 block/blk-exec.c                   | 10 ++++------
 drivers/block/sx8.c                |  4 ++--
 drivers/nvme/host/core.c           |  4 ++--
 drivers/nvme/host/lightnvm.c       |  2 +-
 drivers/nvme/host/pci.c            |  4 ++--
 drivers/nvme/target/passthru.c     |  2 +-
 drivers/scsi/scsi_error.c          |  2 +-
 drivers/scsi/sg.c                  |  3 +--
 drivers/scsi/st.c                  |  2 +-
 drivers/target/target_core_pscsi.c |  3 +--
 include/linux/blkdev.h             |  2 +-
 11 files changed, 17 insertions(+), 21 deletions(-)

diff --git a/block/blk-exec.c b/block/blk-exec.c
index 85324d5..2e37e85 100644
--- a/block/blk-exec.c
+++ b/block/blk-exec.c
@@ -31,8 +31,7 @@ static void blk_end_sync_rq(struct request *rq, blk_status_t error)
 }
 
 /**
- * blk_execute_rq_nowait - insert a request into queue for execution
- * @q:		queue to insert the request in
+ * blk_execute_rq_nowait - insert a request to I/O scheduler for execution
  * @bd_disk:	matching gendisk
  * @rq:		request to insert
  * @at_head:    insert request at head or tail of queue
@@ -45,9 +44,8 @@ static void blk_end_sync_rq(struct request *rq, blk_status_t error)
  * Note:
  *    This function will invoke @done directly if the queue is dead.
  */
-void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
-			   struct request *rq, int at_head,
-			   rq_end_io_fn *done)
+void blk_execute_rq_nowait(struct gendisk *bd_disk, struct request *rq,
+			   int at_head, rq_end_io_fn *done)
 {
 	WARN_ON(irqs_disabled());
 	WARN_ON(!blk_rq_is_passthrough(rq));
@@ -83,7 +81,7 @@ void blk_execute_rq(struct request_queue *q, struct gendisk *bd_disk,
 	unsigned long hang_check;
 
 	rq->end_io_data = &wait;
-	blk_execute_rq_nowait(q, bd_disk, rq, at_head, blk_end_sync_rq);
+	blk_execute_rq_nowait(bd_disk, rq, at_head, blk_end_sync_rq);
 
 	/* Prevent hang_check timer from firing at us during very long I/O */
 	hang_check = sysctl_hung_task_timeout_secs;
diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c
index 4478eb7..2cdf277 100644
--- a/drivers/block/sx8.c
+++ b/drivers/block/sx8.c
@@ -539,7 +539,7 @@ static int carm_array_info (struct carm_host *host, unsigned int array_idx)
 	spin_unlock_irq(&host->lock);
 
 	DPRINTK("blk_execute_rq_nowait, tag == %u\n", rq->tag);
-	blk_execute_rq_nowait(host->oob_q, NULL, rq, true, NULL);
+	blk_execute_rq_nowait(NULL, rq, true, NULL);
 
 	return 0;
 
@@ -578,7 +578,7 @@ static int carm_send_special (struct carm_host *host, carm_sspc_t func)
 	crq->msg_bucket = (u32) rc;
 
 	DPRINTK("blk_execute_rq_nowait, tag == %u\n", rq->tag);
-	blk_execute_rq_nowait(host->oob_q, NULL, rq, true, NULL);
+	blk_execute_rq_nowait(NULL, rq, true, NULL);
 
 	return 0;
 }
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index a39befb..0bea9ae 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -925,7 +925,7 @@ static void nvme_execute_rq_polled(struct request_queue *q,
 
 	rq->cmd_flags |= REQ_HIPRI;
 	rq->end_io_data = &wait;
-	blk_execute_rq_nowait(q, bd_disk, rq, at_head, nvme_end_sync_rq);
+	blk_execute_rq_nowait(bd_disk, rq, at_head, nvme_end_sync_rq);
 
 	while (!completion_done(&wait)) {
 		blk_poll(q, request_to_qc_t(rq->mq_hctx, rq), true);
@@ -1202,7 +1202,7 @@ static int nvme_keep_alive(struct nvme_ctrl *ctrl)
 	rq->timeout = ctrl->kato * HZ;
 	rq->end_io_data = ctrl;
 
-	blk_execute_rq_nowait(rq->q, NULL, rq, 0, nvme_keep_alive_end_io);
+	blk_execute_rq_nowait(NULL, rq, 0, nvme_keep_alive_end_io);
 
 	return 0;
 }
diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index 6c8eab8..0e5a550 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -695,7 +695,7 @@ static int nvme_nvm_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd,
 
 	rq->end_io_data = rqd;
 
-	blk_execute_rq_nowait(q, NULL, rq, 0, nvme_nvm_end_io);
+	blk_execute_rq_nowait(NULL, rq, 0, nvme_nvm_end_io);
 
 	return 0;
 
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 856aa31..5b78e68 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -1357,7 +1357,7 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved)
 	}
 
 	abort_req->end_io_data = NULL;
-	blk_execute_rq_nowait(abort_req->q, NULL, abort_req, 0, abort_endio);
+	blk_execute_rq_nowait(NULL, abort_req, 0, abort_endio);
 
 	/*
 	 * The aborted req will be completed on receiving the abort req.
@@ -2281,7 +2281,7 @@ static int nvme_delete_queue(struct nvme_queue *nvmeq, u8 opcode)
 	req->end_io_data = nvmeq;
 
 	init_completion(&nvmeq->delete_done);
-	blk_execute_rq_nowait(q, NULL, req, false,
+	blk_execute_rq_nowait(NULL, req, false,
 			opcode == nvme_admin_delete_cq ?
 				nvme_del_cq_end : nvme_del_queue_end);
 	return 0;
diff --git a/drivers/nvme/target/passthru.c b/drivers/nvme/target/passthru.c
index b9776fc..cbc88ac 100644
--- a/drivers/nvme/target/passthru.c
+++ b/drivers/nvme/target/passthru.c
@@ -275,7 +275,7 @@ static void nvmet_passthru_execute_cmd(struct nvmet_req *req)
 		schedule_work(&req->p.work);
 	} else {
 		rq->end_io_data = req;
-		blk_execute_rq_nowait(rq->q, ns ? ns->disk : NULL, rq, 0,
+		blk_execute_rq_nowait(ns ? ns->disk : NULL, rq, 0,
 				      nvmet_passthru_req_done);
 	}
 
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index f11f51e..c00f06e 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -2007,7 +2007,7 @@ static void scsi_eh_lock_door(struct scsi_device *sdev)
 	req->timeout = 10 * HZ;
 	rq->retries = 5;
 
-	blk_execute_rq_nowait(req->q, NULL, req, 1, eh_lock_door_done);
+	blk_execute_rq_nowait(NULL, req, 1, eh_lock_door_done);
 }
 
 /**
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index bfa8d77..4383d93 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -829,8 +829,7 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp,
 
 	srp->rq->timeout = timeout;
 	kref_get(&sfp->f_ref); /* sg_rq_end_io() does kref_put(). */
-	blk_execute_rq_nowait(sdp->device->request_queue, sdp->disk,
-			      srp->rq, at_head, sg_rq_end_io);
+	blk_execute_rq_nowait(sdp->disk, srp->rq, at_head, sg_rq_end_io);
 	return 0;
 }
 
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 43f7624..841ad2f 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -585,7 +585,7 @@ static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd,
 	rq->retries = retries;
 	req->end_io_data = SRpnt;
 
-	blk_execute_rq_nowait(req->q, NULL, req, 1, st_scsi_execute_end);
+	blk_execute_rq_nowait(NULL, req, 1, st_scsi_execute_end);
 	return 0;
 }
 
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c
index 7994f27..33770e5 100644
--- a/drivers/target/target_core_pscsi.c
+++ b/drivers/target/target_core_pscsi.c
@@ -1000,8 +1000,7 @@ pscsi_execute_cmd(struct se_cmd *cmd)
 		req->timeout = PS_TIMEOUT_OTHER;
 	scsi_req(req)->retries = PS_RETRY;
 
-	blk_execute_rq_nowait(pdv->pdv_sd->request_queue, NULL, req,
-			(cmd->sam_task_attr == TCM_HEAD_TAG),
+	blk_execute_rq_nowait(NULL, req, (cmd->sam_task_attr == TCM_HEAD_TAG),
 			pscsi_req_done);
 
 	return 0;
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 4526b9e..623a612 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -950,7 +950,7 @@ extern int blk_rq_map_user_iov(struct request_queue *, struct request *,
 			       gfp_t);
 extern void blk_execute_rq(struct request_queue *, struct gendisk *,
 			  struct request *, int);
-extern void blk_execute_rq_nowait(struct request_queue *, struct gendisk *,
+extern void blk_execute_rq_nowait(struct gendisk *,
 				  struct request *, int, rq_end_io_fn *);
 
 /* Helper to convert REQ_OP_XXX to its string format XXX */
-- 
2.7.4



From guoqing.jiang at cloud.ionos.com  Sun Jan 24 23:49:58 2021
From: guoqing.jiang at cloud.ionos.com (Guoqing Jiang)
Date: Mon, 25 Jan 2021 05:49:58 +0100
Subject: [PATCH V3 2/2] block: remove unnecessary argument from blk_execute_rq
In-Reply-To: <1611550198-17142-1-git-send-email-guoqing.jiang@cloud.ionos.com>
References: <1611550198-17142-1-git-send-email-guoqing.jiang@cloud.ionos.com>
Message-ID: <1611550198-17142-3-git-send-email-guoqing.jiang@cloud.ionos.com>

We can remove 'q' from blk_execute_rq as well after the previous change
in blk_execute_rq_nowait.

And more importantly it never really was needed to start with given
that we can trivial derive it from struct request.

Cc: linux-scsi at vger.kernel.org
Cc: virtualization at lists.linux-foundation.org
Cc: linux-ide at vger.kernel.org
Cc: linux-mmc at vger.kernel.org
Cc: linux-nvme at lists.infradead.org
Cc: linux-nfs at vger.kernel.org
Acked-by: Ulf Hansson <ulf.hansson at linaro.org> # for mmc
Signed-off-by: Guoqing Jiang <guoqing.jiang at cloud.ionos.com>
---
 block/blk-exec.c                  |  3 +--
 block/bsg.c                       |  2 +-
 block/scsi_ioctl.c                |  6 +++---
 drivers/block/mtip32xx/mtip32xx.c |  2 +-
 drivers/block/paride/pd.c         |  2 +-
 drivers/block/pktcdvd.c           |  2 +-
 drivers/block/virtio_blk.c        |  2 +-
 drivers/cdrom/cdrom.c             |  2 +-
 drivers/ide/ide-atapi.c           |  2 +-
 drivers/ide/ide-cd.c              |  2 +-
 drivers/ide/ide-cd_ioctl.c        |  2 +-
 drivers/ide/ide-devsets.c         |  2 +-
 drivers/ide/ide-disk.c            |  2 +-
 drivers/ide/ide-ioctls.c          |  4 ++--
 drivers/ide/ide-park.c            |  2 +-
 drivers/ide/ide-pm.c              |  4 ++--
 drivers/ide/ide-tape.c            |  2 +-
 drivers/ide/ide-taskfile.c        |  2 +-
 drivers/mmc/core/block.c          | 10 +++++-----
 drivers/nvme/host/core.c          |  4 ++--
 drivers/nvme/host/lightnvm.c      |  2 +-
 drivers/scsi/scsi_lib.c           |  2 +-
 fs/nfsd/blocklayout.c             |  2 +-
 include/linux/blkdev.h            |  3 +--
 24 files changed, 33 insertions(+), 35 deletions(-)

diff --git a/block/blk-exec.c b/block/blk-exec.c
index 2e37e85..0ab873f 100644
--- a/block/blk-exec.c
+++ b/block/blk-exec.c
@@ -74,8 +74,7 @@ EXPORT_SYMBOL_GPL(blk_execute_rq_nowait);
  *    Insert a fully prepared request at the back of the I/O scheduler queue
  *    for execution and wait for completion.
  */
-void blk_execute_rq(struct request_queue *q, struct gendisk *bd_disk,
-		   struct request *rq, int at_head)
+void blk_execute_rq(struct gendisk *bd_disk, struct request *rq, int at_head)
 {
 	DECLARE_COMPLETION_ONSTACK(wait);
 	unsigned long hang_check;
diff --git a/block/bsg.c b/block/bsg.c
index 3d78e84..bd10922 100644
--- a/block/bsg.c
+++ b/block/bsg.c
@@ -183,7 +183,7 @@ static int bsg_sg_io(struct request_queue *q, fmode_t mode, void __user *uarg)
 
 	bio = rq->bio;
 
-	blk_execute_rq(q, NULL, rq, !(hdr.flags & BSG_FLAG_Q_AT_TAIL));
+	blk_execute_rq(NULL, rq, !(hdr.flags & BSG_FLAG_Q_AT_TAIL));
 	ret = rq->q->bsg_dev.ops->complete_rq(rq, &hdr);
 	blk_rq_unmap_user(bio);
 
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index c9f009c..6599bac 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -357,7 +357,7 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
 	 * (if he doesn't check that is his problem).
 	 * N.B. a non-zero SCSI status is _not_ necessarily an error.
 	 */
-	blk_execute_rq(q, bd_disk, rq, at_head);
+	blk_execute_rq(bd_disk, rq, at_head);
 
 	hdr->duration = jiffies_to_msecs(jiffies - start_time);
 
@@ -493,7 +493,7 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode,
 		goto error;
 	}
 
-	blk_execute_rq(q, disk, rq, 0);
+	blk_execute_rq(disk, rq, 0);
 
 	err = req->result & 0xff;	/* only 8 bit SCSI status */
 	if (err) {
@@ -532,7 +532,7 @@ static int __blk_send_generic(struct request_queue *q, struct gendisk *bd_disk,
 	scsi_req(rq)->cmd[0] = cmd;
 	scsi_req(rq)->cmd[4] = data;
 	scsi_req(rq)->cmd_len = 6;
-	blk_execute_rq(q, bd_disk, rq, 0);
+	blk_execute_rq(bd_disk, rq, 0);
 	err = scsi_req(rq)->result ? -EIO : 0;
 	blk_put_request(rq);
 
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c
index 53ac59d..3fd9983 100644
--- a/drivers/block/mtip32xx/mtip32xx.c
+++ b/drivers/block/mtip32xx/mtip32xx.c
@@ -1015,7 +1015,7 @@ static int mtip_exec_internal_command(struct mtip_port *port,
 	rq->timeout = timeout;
 
 	/* insert request and run queue */
-	blk_execute_rq(rq->q, NULL, rq, true);
+	blk_execute_rq(NULL, rq, true);
 
 	if (int_cmd->status) {
 		dev_err(&dd->pdev->dev, "Internal command [%02X] failed %d\n",
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index a7af4f2..897acda 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -781,7 +781,7 @@ static int pd_special_command(struct pd_unit *disk,
 	req = blk_mq_rq_to_pdu(rq);
 
 	req->func = func;
-	blk_execute_rq(disk->gd->queue, disk->gd, rq, 0);
+	blk_execute_rq(disk->gd, rq, 0);
 	blk_put_request(rq);
 	return 0;
 }
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 658a098..fc4b0f1 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -722,7 +722,7 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *
 	if (cgc->quiet)
 		rq->rq_flags |= RQF_QUIET;
 
-	blk_execute_rq(rq->q, pd->bdev->bd_disk, rq, 0);
+	blk_execute_rq(pd->bdev->bd_disk, rq, 0);
 	if (scsi_req(rq)->result)
 		ret = -EIO;
 out:
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 145606d..b0285db 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -320,7 +320,7 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str)
 	if (err)
 		goto out;
 
-	blk_execute_rq(vblk->disk->queue, vblk->disk, req, false);
+	blk_execute_rq(vblk->disk, req, false);
 	err = blk_status_to_errno(virtblk_result(blk_mq_rq_to_pdu(req)));
 out:
 	blk_put_request(req);
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index 8f0e52a..90ad34c 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -2214,7 +2214,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
 		rq->timeout = 60 * HZ;
 		bio = rq->bio;
 
-		blk_execute_rq(q, cdi->disk, rq, 0);
+		blk_execute_rq(cdi->disk, rq, 0);
 		if (scsi_req(rq)->result) {
 			struct scsi_sense_hdr sshdr;
 
diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c
index 013ad33..a1ce9f5 100644
--- a/drivers/ide/ide-atapi.c
+++ b/drivers/ide/ide-atapi.c
@@ -107,7 +107,7 @@ int ide_queue_pc_tail(ide_drive_t *drive, struct gendisk *disk,
 	memcpy(scsi_req(rq)->cmd, pc->c, 12);
 	if (drive->media == ide_tape)
 		scsi_req(rq)->cmd[13] = REQ_IDETAPE_PC1;
-	blk_execute_rq(drive->queue, disk, rq, 0);
+	blk_execute_rq(disk, rq, 0);
 	error = scsi_req(rq)->result ? -EIO : 0;
 put_req:
 	blk_put_request(rq);
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 25d2d88..cffbcc2 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -467,7 +467,7 @@ int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd,
 			}
 		}
 
-		blk_execute_rq(drive->queue, info->disk, rq, 0);
+		blk_execute_rq(info->disk, rq, 0);
 		error = scsi_req(rq)->result ? -EIO : 0;
 
 		if (buffer)
diff --git a/drivers/ide/ide-cd_ioctl.c b/drivers/ide/ide-cd_ioctl.c
index 46f2df2..011eab9 100644
--- a/drivers/ide/ide-cd_ioctl.c
+++ b/drivers/ide/ide-cd_ioctl.c
@@ -299,7 +299,7 @@ int ide_cdrom_reset(struct cdrom_device_info *cdi)
 	rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0);
 	ide_req(rq)->type = ATA_PRIV_MISC;
 	rq->rq_flags = RQF_QUIET;
-	blk_execute_rq(drive->queue, cd->disk, rq, 0);
+	blk_execute_rq(cd->disk, rq, 0);
 	ret = scsi_req(rq)->result ? -EIO : 0;
 	blk_put_request(rq);
 	/*
diff --git a/drivers/ide/ide-devsets.c b/drivers/ide/ide-devsets.c
index f2f93ed..ca1d4b3 100644
--- a/drivers/ide/ide-devsets.c
+++ b/drivers/ide/ide-devsets.c
@@ -173,7 +173,7 @@ int ide_devset_execute(ide_drive_t *drive, const struct ide_devset *setting,
 	*(int *)&scsi_req(rq)->cmd[1] = arg;
 	ide_req(rq)->special = setting->set;
 
-	blk_execute_rq(q, NULL, rq, 0);
+	blk_execute_rq(NULL, rq, 0);
 	ret = scsi_req(rq)->result;
 	blk_put_request(rq);
 
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index 34b94410..8413731 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -482,7 +482,7 @@ static int set_multcount(ide_drive_t *drive, int arg)
 
 	drive->mult_req = arg;
 	drive->special_flags |= IDE_SFLAG_SET_MULTMODE;
-	blk_execute_rq(drive->queue, NULL, rq, 0);
+	blk_execute_rq(NULL, rq, 0);
 	blk_put_request(rq);
 
 	return (drive->mult_count == arg) ? 0 : -EIO;
diff --git a/drivers/ide/ide-ioctls.c b/drivers/ide/ide-ioctls.c
index 58994da..43fbc37d 100644
--- a/drivers/ide/ide-ioctls.c
+++ b/drivers/ide/ide-ioctls.c
@@ -137,7 +137,7 @@ static int ide_cmd_ioctl(ide_drive_t *drive, void __user *argp)
 
 		rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0);
 		ide_req(rq)->type = ATA_PRIV_TASKFILE;
-		blk_execute_rq(drive->queue, NULL, rq, 0);
+		blk_execute_rq(NULL, rq, 0);
 		err = scsi_req(rq)->result ? -EIO : 0;
 		blk_put_request(rq);
 
@@ -235,7 +235,7 @@ static int generic_drive_reset(ide_drive_t *drive)
 	ide_req(rq)->type = ATA_PRIV_MISC;
 	scsi_req(rq)->cmd_len = 1;
 	scsi_req(rq)->cmd[0] = REQ_DRIVE_RESET;
-	blk_execute_rq(drive->queue, NULL, rq, 1);
+	blk_execute_rq(NULL, rq, 1);
 	ret = scsi_req(rq)->result;
 	blk_put_request(rq);
 	return ret;
diff --git a/drivers/ide/ide-park.c b/drivers/ide/ide-park.c
index 8af7af6..a80a0f2 100644
--- a/drivers/ide/ide-park.c
+++ b/drivers/ide/ide-park.c
@@ -37,7 +37,7 @@ static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout)
 	scsi_req(rq)->cmd_len = 1;
 	ide_req(rq)->type = ATA_PRIV_MISC;
 	ide_req(rq)->special = &timeout;
-	blk_execute_rq(q, NULL, rq, 1);
+	blk_execute_rq(NULL, rq, 1);
 	rc = scsi_req(rq)->result ? -EIO : 0;
 	blk_put_request(rq);
 	if (rc)
diff --git a/drivers/ide/ide-pm.c b/drivers/ide/ide-pm.c
index 82ab308..d680b3e 100644
--- a/drivers/ide/ide-pm.c
+++ b/drivers/ide/ide-pm.c
@@ -27,7 +27,7 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg)
 		mesg.event = PM_EVENT_FREEZE;
 	rqpm.pm_state = mesg.event;
 
-	blk_execute_rq(drive->queue, NULL, rq, 0);
+	blk_execute_rq(NULL, rq, 0);
 	ret = scsi_req(rq)->result ? -EIO : 0;
 	blk_put_request(rq);
 
@@ -50,7 +50,7 @@ static int ide_pm_execute_rq(struct request *rq)
 		blk_mq_end_request(rq, BLK_STS_OK);
 		return -ENXIO;
 	}
-	blk_execute_rq(q, NULL, rq, true);
+	blk_execute_rq(NULL, rq, true);
 
 	return scsi_req(rq)->result ? -EIO : 0;
 }
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index 88b9643..fa05e7e 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -868,7 +868,7 @@ static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int size)
 			goto out_put;
 	}
 
-	blk_execute_rq(drive->queue, tape->disk, rq, 0);
+	blk_execute_rq(tape->disk, rq, 0);
 
 	/* calculate the number of transferred bytes and update buffer state */
 	size -= scsi_req(rq)->resid_len;
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index d016cbe..6665fc4 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -443,7 +443,7 @@ int ide_raw_taskfile(ide_drive_t *drive, struct ide_cmd *cmd, u8 *buf,
 	ide_req(rq)->special = cmd;
 	cmd->rq = rq;
 
-	blk_execute_rq(drive->queue, NULL, rq, 0);
+	blk_execute_rq(NULL, rq, 0);
 	error = scsi_req(rq)->result ? -EIO : 0;
 put_req:
 	blk_put_request(rq);
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index 42e27a2..a1d6b68 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -253,7 +253,7 @@ static ssize_t power_ro_lock_store(struct device *dev,
 		goto out_put;
 	}
 	req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_BOOT_WP;
-	blk_execute_rq(mq->queue, NULL, req, 0);
+	blk_execute_rq(NULL, req, 0);
 	ret = req_to_mmc_queue_req(req)->drv_op_result;
 	blk_put_request(req);
 
@@ -629,7 +629,7 @@ static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md,
 		rpmb ? MMC_DRV_OP_IOCTL_RPMB : MMC_DRV_OP_IOCTL;
 	req_to_mmc_queue_req(req)->drv_op_data = idatas;
 	req_to_mmc_queue_req(req)->ioc_count = 1;
-	blk_execute_rq(mq->queue, NULL, req, 0);
+	blk_execute_rq(NULL, req, 0);
 	ioc_err = req_to_mmc_queue_req(req)->drv_op_result;
 	err = mmc_blk_ioctl_copy_to_user(ic_ptr, idata);
 	blk_put_request(req);
@@ -698,7 +698,7 @@ static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md,
 		rpmb ? MMC_DRV_OP_IOCTL_RPMB : MMC_DRV_OP_IOCTL;
 	req_to_mmc_queue_req(req)->drv_op_data = idata;
 	req_to_mmc_queue_req(req)->ioc_count = num_of_cmds;
-	blk_execute_rq(mq->queue, NULL, req, 0);
+	blk_execute_rq(NULL, req, 0);
 	ioc_err = req_to_mmc_queue_req(req)->drv_op_result;
 
 	/* copy to user if data and response */
@@ -2722,7 +2722,7 @@ static int mmc_dbg_card_status_get(void *data, u64 *val)
 	if (IS_ERR(req))
 		return PTR_ERR(req);
 	req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_GET_CARD_STATUS;
-	blk_execute_rq(mq->queue, NULL, req, 0);
+	blk_execute_rq(NULL, req, 0);
 	ret = req_to_mmc_queue_req(req)->drv_op_result;
 	if (ret >= 0) {
 		*val = ret;
@@ -2761,7 +2761,7 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp)
 	}
 	req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_GET_EXT_CSD;
 	req_to_mmc_queue_req(req)->drv_op_data = &ext_csd;
-	blk_execute_rq(mq->queue, NULL, req, 0);
+	blk_execute_rq(NULL, req, 0);
 	err = req_to_mmc_queue_req(req)->drv_op_result;
 	blk_put_request(req);
 	if (err) {
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 0bea9ae..eb7963f 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -964,7 +964,7 @@ int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
 	if (poll)
 		nvme_execute_rq_polled(req->q, NULL, req, at_head);
 	else
-		blk_execute_rq(req->q, NULL, req, at_head);
+		blk_execute_rq(NULL, req, at_head);
 	if (result)
 		*result = nvme_req(req)->result;
 	if (nvme_req(req)->flags & NVME_REQ_CANCELLED)
@@ -1101,7 +1101,7 @@ void nvme_execute_passthru_rq(struct request *rq)
 	u32 effects;
 
 	effects = nvme_passthru_start(ctrl, ns, cmd->common.opcode);
-	blk_execute_rq(rq->q, disk, rq, 0);
+	blk_execute_rq(disk, rq, 0);
 	nvme_passthru_end(ctrl, effects);
 }
 EXPORT_SYMBOL_NS_GPL(nvme_execute_passthru_rq, NVME_TARGET_PASSTHRU);
diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index 0e5a550..ec38128 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -819,7 +819,7 @@ static int nvme_nvm_submit_user_cmd(struct request_queue *q,
 		bio->bi_bdev = ns->disk->part0;
 	}
 
-	blk_execute_rq(q, NULL, rq, 0);
+	blk_execute_rq(NULL, rq, 0);
 
 	if (nvme_req(rq)->flags & NVME_REQ_CANCELLED)
 		ret = -EINTR;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index b3f14f0..4d22806 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -269,7 +269,7 @@ int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
 	/*
 	 * head injection *required* here otherwise quiesce won't work
 	 */
-	blk_execute_rq(req->q, NULL, req, 1);
+	blk_execute_rq(NULL, req, 1);
 
 	/*
 	 * Some devices (USB mass-storage in particular) may transfer
diff --git a/fs/nfsd/blocklayout.c b/fs/nfsd/blocklayout.c
index a07c39c..1058659 100644
--- a/fs/nfsd/blocklayout.c
+++ b/fs/nfsd/blocklayout.c
@@ -254,7 +254,7 @@ static int nfsd4_scsi_identify_device(struct block_device *bdev,
 	req->cmd[4] = bufflen & 0xff;
 	req->cmd_len = COMMAND_SIZE(INQUIRY);
 
-	blk_execute_rq(rq->q, NULL, rq, 1);
+	blk_execute_rq(NULL, rq, 1);
 	if (req->result) {
 		pr_err("pNFS: INQUIRY 0x83 failed with: %x\n",
 			req->result);
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 623a612..20f3706 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -948,8 +948,7 @@ extern int blk_rq_map_kern(struct request_queue *, struct request *, void *, uns
 extern int blk_rq_map_user_iov(struct request_queue *, struct request *,
 			       struct rq_map_data *, const struct iov_iter *,
 			       gfp_t);
-extern void blk_execute_rq(struct request_queue *, struct gendisk *,
-			  struct request *, int);
+extern void blk_execute_rq(struct gendisk *, struct request *, int);
 extern void blk_execute_rq_nowait(struct gendisk *,
 				  struct request *, int, rq_end_io_fn *);
 
-- 
2.7.4



From axboe at kernel.dk  Sun Jan 24 23:53:29 2021
From: axboe at kernel.dk (Jens Axboe)
Date: Sun, 24 Jan 2021 21:53:29 -0700
Subject: [PATCH V3 0/2] remove unused argument from blk_execute_rq_nowait
 and blk_execute_rq
In-Reply-To: <1611550198-17142-1-git-send-email-guoqing.jiang@cloud.ionos.com>
References: <1611550198-17142-1-git-send-email-guoqing.jiang@cloud.ionos.com>
Message-ID: <50c4cdb5-b5ea-5431-c319-a6784f33f8b6@kernel.dk>

On 1/24/21 9:49 PM, Guoqing Jiang wrote:
> V3 changes:
> 1. rebase with for-5.12/block branch.
> 2. add Ulf's Acked-by.
> 
> V2 changes:
> 1. update commit header per Christoph's comment.
> 
> Hi Jens,
> 
> This series remove unused 'q' from blk_execute_rq_nowait and blk_execute_rq.
> Also update the comment for blk_execute_rq_nowait.
> 

Applied, thanks.

-- 
Jens Axboe



From Damien.LeMoal at wdc.com  Mon Jan 25 00:32:05 2021
From: Damien.LeMoal at wdc.com (Damien Le Moal)
Date: Mon, 25 Jan 2021 05:32:05 +0000
Subject: [PATCH v3 1/3] block: introduce zone_write_granularity limit
References: <20210122080014.174391-1-damien.lemoal@wdc.com>
 <20210122080014.174391-2-damien.lemoal@wdc.com>
 <20210122084209.GA15710@lst.de>
 <BL0PR04MB6514A2655635DFF482E4252BE7A00@BL0PR04MB6514.namprd04.prod.outlook.com>
 <20210124100724.GA27580@lst.de>
Message-ID: <BL0PR04MB6514C3C43A5E3DA84632188CE7BD9@BL0PR04MB6514.namprd04.prod.outlook.com>

On 2021/01/24 19:07, Christoph Hellwig wrote:
> On Fri, Jan 22, 2021 at 08:56:58AM +0000, Damien Le Moal wrote:
>>> This looks a little strange.  If we special case zoned vs not zoned
>>> here anyway, why not set the zone_write_granularity to the logical
>>> block size here by default.
>>
>> The convention is zone_write_granularity == 0 for the BLK_ZONED_NONE case. Hence
>> the reset here if we force the zoned model to none for HA drives. This way, this
>> does not create a special case for HA drives used as regular disks.
> 
> Just inititialize it for all cases if you initialize it for some here.
> That way everyone but sd already gets a right default and life becomes
> simpler.

True for nullblk, and that also simplifies sd a little. But not for nvme,
blk_queue_set_zoned() is not used AND nvme_update_zone_info() is called before
nvme_update_disk_info() where the NS logical block size is set. So some
surgery/cleanups would be needed to benefit. I could add a cleanup for this, but
not entirely sure if calling nvme_update_zone_info() after
nvme_update_disk_info() is OK. Thoughts ?


-- 
Damien Le Moal
Western Digital Research


From Damien.LeMoal at wdc.com  Mon Jan 25 00:34:59 2021
From: Damien.LeMoal at wdc.com (Damien Le Moal)
Date: Mon, 25 Jan 2021 05:34:59 +0000
Subject: [PATCH v3 1/3] block: introduce zone_write_granularity limit
References: <20210122080014.174391-1-damien.lemoal@wdc.com>
 <20210122080014.174391-2-damien.lemoal@wdc.com>
 <20210122084209.GA15710@lst.de>
 <BL0PR04MB6514A2655635DFF482E4252BE7A00@BL0PR04MB6514.namprd04.prod.outlook.com>
 <20210124100724.GA27580@lst.de>
 <BL0PR04MB6514C3C43A5E3DA84632188CE7BD9@BL0PR04MB6514.namprd04.prod.outlook.com>
Message-ID: <BL0PR04MB6514818B1A57DCE4AE9BA5BBE7BD9@BL0PR04MB6514.namprd04.prod.outlook.com>

On 2021/01/25 14:32, Damien Le Moal wrote:
> On 2021/01/24 19:07, Christoph Hellwig wrote:
>> On Fri, Jan 22, 2021 at 08:56:58AM +0000, Damien Le Moal wrote:
>>>> This looks a little strange.  If we special case zoned vs not zoned
>>>> here anyway, why not set the zone_write_granularity to the logical
>>>> block size here by default.
>>>
>>> The convention is zone_write_granularity == 0 for the BLK_ZONED_NONE case. Hence
>>> the reset here if we force the zoned model to none for HA drives. This way, this
>>> does not create a special case for HA drives used as regular disks.
>>
>> Just inititialize it for all cases if you initialize it for some here.
>> That way everyone but sd already gets a right default and life becomes
>> simpler.
> 
> True for nullblk, and that also simplifies sd a little. But not for nvme,
> blk_queue_set_zoned() is not used AND nvme_update_zone_info() is called before
> nvme_update_disk_info() where the NS logical block size is set. So some
> surgery/cleanups would be needed to benefit. I could add a cleanup for this, but
> not entirely sure if calling nvme_update_zone_info() after
> nvme_update_disk_info() is OK. Thoughts ?

Also, because nvme_update_zone_info() is called without the logical block size
being set yet, this patch was not good for ZNS.




-- 
Damien Le Moal
Western Digital Research


From Niklas.Cassel at wdc.com  Mon Jan 25 03:16:55 2021
From: Niklas.Cassel at wdc.com (Niklas Cassel)
Date: Mon, 25 Jan 2021 08:16:55 +0000
Subject: Problem with SPCC 256GB NVMe 1.3 drive - refcount_t: underflow;
 use-after-free.
In-Reply-To: <23f49172-5d0e-618a-199d-d568f695dc30@comcast.net>
References: <f50bc59c-db11-bb44-55be-7b9db1119872@comcast.net>
 <BYAPR04MB49659C0F0F0E11D166B31E0586A40@BYAPR04MB4965.namprd04.prod.outlook.com>
 <a4c75497-d170-1e0f-8608-282231ff3a8e@comcast.net>
 <BYAPR04MB496542BEF594F0380F7D41CF86A20@BYAPR04MB4965.namprd04.prod.outlook.com>
 <df46d7ce-ce70-1f43-0efd-7153761bcff0@comcast.net>
 <20210121124459.GA156577@localhost.localdomain>
 <c48abecf-8e4f-b76a-c751-1a0d239c99b3@comcast.net>
 <BYAPR04MB4965404638B4C43DBA577D1686A00@BYAPR04MB4965.namprd04.prod.outlook.com>
 <BYAPR04MB4965342B52D5C3C6D8A7892D86A00@BYAPR04MB4965.namprd04.prod.outlook.com>
 <23f49172-5d0e-618a-199d-d568f695dc30@comcast.net>
Message-ID: <20210125081654.GA226984@localhost.localdomain>

On Fri, Jan 22, 2021 at 07:54:26PM -0500, Bradley Chapman wrote:
> With the following patch applied to the NVMe tree, my system hard-locked and
> would not respond to Alt+SysRQ once I mounted the filesystem and attempted a
> directory listing of the root of the filesystem.
> 
> diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
> index 25456d02eddb..7ba5e8e92e19 100644
> --- a/drivers/nvme/host/pci.c
> +++ b/drivers/nvme/host/pci.c
> @@ -3228,6 +3228,8 @@ static const struct pci_device_id nvme_id_table[] = {
>                 .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
>         { PCI_DEVICE(0x15b7, 0x2001),   /*  Sandisk Skyhawk */
>                 .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
> +       { PCI_DEVICE(0x1d97, 0x2263),   /*  SPCC */
> +               .driver_data = NVME_QUIRK_SINGLE_VECTOR },
>         { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2001),
>                 .driver_data = NVME_QUIRK_SINGLE_VECTOR },
>         { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2003) },
> 

Hello Bradley,

Chaitanya asked you to test the NVME_QUIRK_DISABLE_WRITE_ZEROES quirk.
Your patch seems to instead use the NVME_QUIRK_SINGLE_VECTOR quirk.

Did you try the NVME_QUIRK_DISABLE_WRITE_ZEROES quirk?


Kind regards,
Niklas

From Chaitanya.Kulkarni at wdc.com  Mon Jan 25 03:34:11 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Mon, 25 Jan 2021 08:34:11 +0000
Subject: Problem with SPCC 256GB NVMe 1.3 drive - refcount_t: underflow;
 use-after-free.
In-Reply-To: <20210125081654.GA226984@localhost.localdomain>
References: <f50bc59c-db11-bb44-55be-7b9db1119872@comcast.net>
 <BYAPR04MB49659C0F0F0E11D166B31E0586A40@BYAPR04MB4965.namprd04.prod.outlook.com>
 <a4c75497-d170-1e0f-8608-282231ff3a8e@comcast.net>
 <BYAPR04MB496542BEF594F0380F7D41CF86A20@BYAPR04MB4965.namprd04.prod.outlook.com>
 <df46d7ce-ce70-1f43-0efd-7153761bcff0@comcast.net>
 <20210121124459.GA156577@localhost.localdomain>
 <c48abecf-8e4f-b76a-c751-1a0d239c99b3@comcast.net>
 <BYAPR04MB4965404638B4C43DBA577D1686A00@BYAPR04MB4965.namprd04.prod.outlook.com>
 <BYAPR04MB4965342B52D5C3C6D8A7892D86A00@BYAPR04MB4965.namprd04.prod.outlook.com>
 <23f49172-5d0e-618a-199d-d568f695dc30@comcast.net>,
 <20210125081654.GA226984@localhost.localdomain>
Message-ID: <6709E718-ABD5-4B69-B4E7-883C4E4CD178@wdc.com>

I have pointed that out on friday already offline to reduce the mailing list noise. 

> On Jan 25, 2021, at 12:16 AM, Niklas Cassel <Niklas.Cassel at wdc.com> wrote:
> 
> ?On Fri, Jan 22, 2021 at 07:54:26PM -0500, Bradley Chapman wrote:
>> With the following patch applied to the NVMe tree, my system hard-locked and
>> would not respond to Alt+SysRQ once I mounted the filesystem and attempted a
>> directory listing of the root of the filesystem.
>> 
>> diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
>> index 25456d02eddb..7ba5e8e92e19 100644
>> --- a/drivers/nvme/host/pci.c
>> +++ b/drivers/nvme/host/pci.c
>> @@ -3228,6 +3228,8 @@ static const struct pci_device_id nvme_id_table[] = {
>>                .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
>>        { PCI_DEVICE(0x15b7, 0x2001),   /*  Sandisk Skyhawk */
>>                .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
>> +       { PCI_DEVICE(0x1d97, 0x2263),   /*  SPCC */
>> +               .driver_data = NVME_QUIRK_SINGLE_VECTOR },
>>        { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2001),
>>                .driver_data = NVME_QUIRK_SINGLE_VECTOR },
>>        { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2003) },
>> 
> 
> Hello Bradley,
> 
> Chaitanya asked you to test the NVME_QUIRK_DISABLE_WRITE_ZEROES quirk.
> Your patch seems to instead use the NVME_QUIRK_SINGLE_VECTOR quirk.
> 
> Did you try the NVME_QUIRK_DISABLE_WRITE_ZEROES quirk?
> 
> 
> Kind regards,
> Niklas

From claus.stovgaard at gmail.com  Mon Jan 25 11:00:57 2021
From: claus.stovgaard at gmail.com (Claus Stovgaard)
Date: Mon, 25 Jan 2021 17:00:57 +0100
Subject: Missing or invalid SUBNQN on Corsair MP600 1TB device
Message-ID: <04fdb6a116bbc4d9eadc3f9434d8b6f2426e3c57.camel@gmail.com>

Hi

This is my first post to this mailing list, so please forgive me if it
is already discussed.

I have just build a new workstation, where I noticed the following
warning for the Corsair MP600 1 TB drive.

nvme nvme0: missing or invalid SUBNQN field.

it arrived with firmware 11.3 and I have later upgraded to firmware
13.0 to see if they have fixed the firmware.

Have also reported in their forum
https://forum.corsair.com/forums/showthread.php?p=1077109#post1077109

Looking in the host pci.c code it seems to be a known issue on some
drives where the "NVME_QUIRK_IGNORE_DEV_SUBNQN" is used.

So I guess that Corsair MP600 is a candidate for the same quirk.

Considered to add the Corsair to the list of drives with
NVME_QUIRK_IGNORE_DEV_SUBNQN, but would just ask here first, if it
would be the correct use and understanding.

Regards Claus

Below is info for my system for reference.

nova /home/frosteyes # uname -a
Linux nova 5.10.10-gentoo-FrostEyes #1 SMP PREEMPT Sun Jan 24 23:26:32
CET 2021 x86_64 AMD Ryzen 9 5950X 16-Core Processor AuthenticAMD
GNU/Linux

nova /home/frosteyes # journalctl -b | grep nvme0
jan 24 23:32:23 nova kernel: nvme nvme0: pci function 0000:01:00.0
jan 24 23:32:23 nova kernel: nvme nvme0: missing or invalid SUBNQN
field.
jan 24 23:32:23 nova kernel: nvme nvme0: Shutdown timeout set to 10
seconds
jan 24 23:32:23 nova kernel: nvme nvme0: 8/0/0 default/read/poll queues
jan 24 23:32:23 nova kernel:  nvme0n1: p1 p2

nova /home/frosteyes # nvme list
Node             SN                   Model                            
        Namespace Usage                      Format           FW Rev  
---------------- -------------------- -------------------------------
--------- --------- -------------------------- ---------------- -----
---
/dev/nvme0n1     203982290001285542EC Force
MP600                              1           1,00  TB
/   1,00  TB    512   B +  0 B   EGFM13.0

nova /home/frosteyes # lspci -v -nn -s 1:00
01:00.0 Non-Volatile memory controller [0108]: Phison Electronics
Corporation E16 PCIe4 NVMe Controller [1987:5016] (rev 01) (prog-if 02
[NVM Express])
        Subsystem: Phison Electronics Corporation E16 PCIe4 NVMe
Controller [1987:5016]
        Flags: bus master, fast devsel, latency 0, IRQ 42, NUMA node 0
        Memory at fcf00000 (64-bit, non-prefetchable) [size=16K]
        Capabilities: [80] Express Endpoint, MSI 00
        Capabilities: [d0] MSI-X: Enable+ Count=9 Masked-
        Capabilities: [e0] MSI: Enable- Count=1/8 Maskable- 64bit+
        Capabilities: [f8] Power Management version 3
        Capabilities: [100] Latency Tolerance Reporting
        Capabilities: [110] L1 PM Substates
        Capabilities: [128] Alternative Routing-ID Interpretation (ARI)
        Capabilities: [1e0] Data Link Feature <?>
        Capabilities: [200] Advanced Error Reporting
        Capabilities: [300] Secondary PCI Express
        Capabilities: [340] Physical Layer 16.0 GT/s <?>
        Capabilities: [378] Lane Margining at the Receiver <?>
        Kernel driver in use: nvme



From mark.wunderlich at intel.com  Mon Jan 25 12:50:24 2021
From: mark.wunderlich at intel.com (Wunderlich, Mark)
Date: Mon, 25 Jan 2021 17:50:24 +0000
Subject: [RFC PATCH 0/2] nvmet-tcp: introduce idle poll option
In-Reply-To: <62cf6b4c-3b8b-db9f-f960-85efaf0896b6@grimberg.me>
References: <BYAPR11MB2869A106FF8E7D7FEAD30EF1E5C60@BYAPR11MB2869.namprd11.prod.outlook.com>
 <62cf6b4c-3b8b-db9f-f960-85efaf0896b6@grimberg.me>
Message-ID: <BYAPR11MB286948DC9BB8251F57A00D2CE5BD9@BYAPR11MB2869.namprd11.prod.outlook.com>

>Hey Mark,

On 12/14/20 5:11 PM, Wunderlich, Mark wrote:
>> This RFC 2 patch series was created as an alternative solution to the previous series I submitted back on 8/27/2020 [nvmet_tcp: introduce poll groups and polling optimizations], where only the first patch in that series was accepted.  This series is greatly simplified from that previous patch series in that it does not explicitly create managed/tracked poll groups, with the io_work() function processing of a single queue preserved.  This simplified patch series relies on the accepted new queue context assignment to so_incoming_cpu to logically maintain shared processing of a logical group of queues on the same CPU core.
>> 
>> What this new patch pair provides is twofold. First, it introduces changes and a new nvmet-tcp module option 'idle_poll_period' that enables the kworker for a given queue to persistently get re-queued until the queue is sensed as being 'idle'.  Idle being determined as being when there is no new requests or pending backend device completions for the specified 'idle_poll_period' length of time.  By allowing this type of persistent poll behavior it is then possible to introduce the capability contained in the second patch of the set, this being the ability to have the kworker directly poll a backend NVMe device for completions instead of waiting for the NVMe device to interrupt and push out completions.
>> 
>> The data below shows that this new polling option, and removing of NVMe device interrupts, can have a benefit to performance.  But it is understood that this change prototype has some drawbacks, one specifically being how the nvmet-tcp module is being allowed to directly call the newly introduced block layer poll once function which can be considered a layering violation.  But in it's current state the patch series at least is a means to open discussion towards the benefits of working towards enabling such a polling model.  Is it a sound concept, but best implemented in the nvme target core layer instead?  Maybe moving away from using kworkers and having more dedicated core service tasks for logical queue groups?
>> 
>> The following test data was collected using the following config:
>> . FIO io_uring, using HIPRI option
>> . 4 FIO jobs, each directed at 3 NVMe device namespaces, each with 4 threads pinned to isolated NUMA node CPU close to NIC for total of 16 active thread connections.
>> . 4K, random read I/O pattern
>> . Queue Depth 32, Batch size 8
>> . Initiator NIC HW queues set to 52 (number of local NUMA cores), HW queue affinity set to local NUMA cores.
>> . Target NIC HW queues set to 8 , HW queue affinity set to local NUMA cores.
>> . Initiator to Target connected using 1 default, 32 poll queues.
>> . When testing with 'idle_poll_period' enabled, to test polling NVMe devices, the target NVMe module loaded with module option to enable 16 poll queues.
>> . Patches tested and developed on linux-nvme nvme-5.10 branch.
>> . All measured times in usecs unless otherwise noted.
>> . Fewer target HW queues vs. number of active connections to measure the impact of virtual grouping of connection processing on shared target cores.
>> 
>> Baseline - patches not applied
>> IOPS(k)? ?????????????? Avg Lat??????????????? 99.99???? 99.90???? 99.00???? Stdev??????????????????? Context Switch? ?????????????? Tgt. CPU Util.
>> 1910???????????????????? 252.92????????????????? 685??????? 578??????? 
>> 502??????? 98.45??????????????????? ~215K?????????????????? ?????????????? 
>> 801.37
>> 
>> Patches applied on target - module option 'idle_poll_period' not set.
>> 2152???????????????????? 223.31????????????????? 685??????? 611??????? 
>> 424??????? 92.11??????????????????? ~120K?????????????????? ?????????????? 
>> 882.14
>> 
>> Patches applied on target - module option 'idle_poll_period' set to 
>> 750000 usecs. (NVMe module not enabling poll queues)
>> 2227???????????????????? 216.65????????????????? 627??????? 553??????? 
>> 388??????? 69.48??????????????????? ~100-400???????????? ?????????????? 
>> 934.35
>> 
>> Patches applied on target - module option 'idle_poll_period' set to 750000 usecs. NVMe module loaded enabling 16 poll queues.
>> 2779???????????????????? 168.60????????????????? 545??????? 474??????? 
>> 375??????? 53.24??????????????????? ~100-400???????????? ?????????????? 
>> 802
>> 
>> This data shows that adding the new idle poll option does not impact performance when not used.  When used with the addition of direct NVMe device polling for completions, there is a nice performance benefit.
>> It was noted during testing that logical grouping of queues to cores on the target can vary as a result of RSS which will or without this patch series which can vary the performance achieved, but when using the patch set with direct NVMe device polling then the logical queue grouping was more consistent and performance varied less.

>So it does seem that polling the backend devices does have merit, and the command tracking indicator if we should poll the backend devices is an interesting idea.

>However this should something that should really be handled by nvmet core. We could potentially add some counters to nvmet_sq and/or nvmet_cq.

>My difficulty is to understand if we can move the I/O threads from the transport drivers to the core. Right now the I/O contexts are provided by either the transports or the backend devices. IFF we want to explore this (and as I said, you clearly showed it has merit), we would need to explore if moving the I/O context and build transport_poll/transport_wait sort of interface for this.

I can understand the architectural direction that such a polling thread is better to be performed within the core, my initial goal being isolated to demonstrate goodness within TCP implementation itself with as minimal change as required in other areas.  I hope a move to the core could remain an optional feature that other transports would not be expected, or forced, to accept.  Would the best approach in moving to a core centric model be to first introduce the core specific thread context option, then follow that with the changes to allow non-blocking device polling (and whatever request tracking may still be required) from such thread contexts?

This RFC would align with this phased approach, given that the first part is targeted at improvement to io_work() thread to better service transport interfaces that benefit from a more active polled model.  Then the second part that focused on enabling the ability to have non-blocking polled access to NVMe device poll queues.

>This can be done for tcp/rdma and loop for sure, but I'm not sure what we can do for FC (but maybe this is possible, need to look further).

>Adding Chaitanya who looked into device polling in the past to get his feedback if this is something interesting.

Ah, would be great to hear your thoughts on this Chaitanya, given your experience.

From kbusch at kernel.org  Mon Jan 25 12:58:27 2021
From: kbusch at kernel.org (Keith Busch)
Date: Mon, 25 Jan 2021 09:58:27 -0800
Subject: Missing or invalid SUBNQN on Corsair MP600 1TB device
In-Reply-To: <04fdb6a116bbc4d9eadc3f9434d8b6f2426e3c57.camel@gmail.com>
References: <04fdb6a116bbc4d9eadc3f9434d8b6f2426e3c57.camel@gmail.com>
Message-ID: <20210125175827.GA1732047@dhcp-10-100-145-180.wdc.com>

On Mon, Jan 25, 2021 at 05:00:57PM +0100, Claus Stovgaard wrote:
> I have just build a new workstation, where I noticed the following
> warning for the Corsair MP600 1 TB drive.
> 
> nvme nvme0: missing or invalid SUBNQN field.
> 
> it arrived with firmware 11.3 and I have later upgraded to firmware
> 13.0 to see if they have fixed the firmware.
> 
> Have also reported in their forum
> https://forum.corsair.com/forums/showthread.php?p=1077109#post1077109
> 
> Looking in the host pci.c code it seems to be a known issue on some
> drives where the "NVME_QUIRK_IGNORE_DEV_SUBNQN" is used.
> 
> So I guess that Corsair MP600 is a candidate for the same quirk.
> 
> Considered to add the Corsair to the list of drives with
> NVME_QUIRK_IGNORE_DEV_SUBNQN, but would just ask here first, if it
> would be the correct use and understanding.

Yes, that is the correct quirk to use with devices reporting spec
revision 1.2.1 compatibility but are not compliant with the subsys nqn
field. The device should continue to work without the quirk, but you'll
get the warning.


From clay.mayers at kioxia.com  Mon Jan 25 14:58:42 2021
From: clay.mayers at kioxia.com (clay.mayers at kioxia.com)
Date: Mon, 25 Jan 2021 11:58:42 -0800
Subject: [PATCH V2 0/2] nvme: Support for fused NVME_IOCTL_SUBMIT_IO
In-Reply-To: <20210105224939.1336-2-clay.mayers@kioxia.com>
References: <20210105224939.1336-2-clay.mayers@kioxia.com>
Message-ID: <20210125195844.1390581-1-clay.mayers@kioxia.com>

From: Clay Mayers <clay.mayers at kioxia.com>

Enables fused compare/write to be issued from user mode.

The first patch allows a pair of pass through requests
to be linked and submitted as a fused pair to the nvme
pci device queue.  The second patch exposes it through
an nvme ioctl so a fused pair can be issued from user
mode.

There was a question regarding Linux support for this
functionality in nvme-cli.  With these patches, that
would be possible.

https://github.com/linux-nvme/nvme-cli/issues/318

Local pci device fused support is also necessary for
NVMeOF targets to support fused operation.

Clay Mayers (2):
  nvme: support fused pci nvme requests
  nvme: support fused NVME_IOCTL_SUBMIT_IO

 drivers/nvme/host/core.c | 267 ++++++++++++++++++++++++++++++---------
 drivers/nvme/host/nvme.h |  12 ++
 drivers/nvme/host/pci.c  |  85 ++++++++++++-
 3 files changed, 302 insertions(+), 62 deletions(-)

-- 
2.27.0



From clay.mayers at kioxia.com  Mon Jan 25 14:58:43 2021
From: clay.mayers at kioxia.com (clay.mayers at kioxia.com)
Date: Mon, 25 Jan 2021 11:58:43 -0800
Subject: [PATCH V2 1/2] nvme: support fused pci nvme requests
In-Reply-To: <20210105224939.1336-2-clay.mayers@kioxia.com>
References: <20210105224939.1336-2-clay.mayers@kioxia.com>
Message-ID: <20210125195844.1390581-2-clay.mayers@kioxia.com>

From: Clay Mayers <clay.mayers at kioxia.com>

Adds support for fused nvme commands to be tunneled through a blk_mq
queue and submitted atomically to a pci nvme device queue.

In nvme_queue_rq(), when an nvme cmnd has the first fused flag set,
the nvme cmnd is saved in nvme_request.fctx and the command is not
queued to the device.  Once the nvme cmnd with the second fused flag
set is queued, nvme_request.nrq is used to get back to the first
fused request so both cmnds can be queued to the device atomically.

v2:
Reduced size of nvme_request by pointing to saved cmnd instead so
only fused commands require the extra 64 bytes.  The saved cmnd is
now with the first request to ease clean up.  Flipped second req
to point to the first so a union with the saved cmnd pointer can
be used to limit the fused impact to 8 bytes.

Fixed issue with aborted first fused cmnd being submitted by
unaborted second fused cmnd.

Signed-off-by: Clay Mayers <clay.mayers at kioxia.com>
---
 drivers/nvme/host/nvme.h | 12 ++++++
 drivers/nvme/host/pci.c  | 85 ++++++++++++++++++++++++++++++++++++++--
 2 files changed, 94 insertions(+), 3 deletions(-)

diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 567f7ad18a91..b41ce7cd4f49 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -157,6 +157,18 @@ struct nvme_request {
 	u8			flags;
 	u16			status;
 	struct nvme_ctrl	*ctrl;
+	union {
+		struct nvme_request *nrq;	/* other fused request */
+		/*
+		 * Between the time the first fused is queued with nvme_queue_rq
+		 * and the second command is queued, the first fused command
+		 * uses fctx instead of nrq.
+		 */
+		struct nvme_fused_ctx {
+			struct nvme_request *nrq2;	/* copy of nrq */
+			struct nvme_command cmnd;	/* copy of 1st fused */
+		} *fctx;
+	};
 };
 
 /*
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 3be352403839..ba4798685811 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -491,6 +491,30 @@ static inline void nvme_write_sq_db(struct nvme_queue *nvmeq, bool write_sq)
 	nvmeq->last_sq_tail = nvmeq->sq_tail;
 }
 
+/**
+ * nvme_submit_cmd2() - Copy fused commands into a queue and ring the doorbell
+ * @nvmeq: The queue to use
+ * @cmd: The first command to send
+ * @cmd2: the second command to send
+ * @write_sq: whether to write to the SQ doorbell
+ */
+static void nvme_submit_cmd2(struct nvme_queue *nvmeq, struct nvme_command *cmd,
+			     struct nvme_command *cmd2, bool write_sq)
+{
+	spin_lock(&nvmeq->sq_lock);
+	memcpy(nvmeq->sq_cmds + (nvmeq->sq_tail << nvmeq->sqes),
+		cmd, sizeof(*cmd));
+	if (++nvmeq->sq_tail == nvmeq->q_depth)
+		nvmeq->sq_tail = 0;
+	memcpy(nvmeq->sq_cmds + (nvmeq->sq_tail << nvmeq->sqes),
+		cmd2, sizeof(*cmd2));
+	if (++nvmeq->sq_tail == nvmeq->q_depth)
+		nvmeq->sq_tail = 0;
+	nvme_write_sq_db(nvmeq, write_sq);
+	spin_unlock(&nvmeq->sq_lock);
+}
+
+
 /**
  * nvme_submit_cmd() - Copy a command into a queue and ring the doorbell
  * @nvmeq: The queue to use
@@ -876,6 +900,37 @@ static blk_status_t nvme_map_metadata(struct nvme_dev *dev, struct request *req,
 	return BLK_STS_OK;
 }
 
+static blk_status_t nvme_queue_frq(struct nvme_queue *nvmeq,
+			struct request *req, struct nvme_command *cmnd,
+			bool write_sq)
+{
+	struct nvme_fused_ctx *fctx;
+
+	if (cmnd->common.flags & NVME_CMD_FUSE_FIRST) {
+		/* Save cmnd to submit with 2nd fused */
+		fctx = kmalloc(sizeof(*fctx), GFP_KERNEL);
+		if (!fctx)
+			return BLK_STS_RESOURCE;
+		fctx->nrq2 = nvme_req(req)->nrq;
+		memcpy(&fctx->cmnd, cmnd, sizeof(*cmnd));
+		nvme_req(req)->fctx = fctx;
+		blk_mq_start_request(req);
+		return BLK_STS_OK;
+	}
+	/* handle NVME_CMD_FUSED_SECOND */
+	if (!nvme_req(req)->nrq) {
+		nvme_req(req)->status = NVME_SC_FUSED_FAIL;
+		return BLK_STS_IOERR;	/* First i/o has been canceled */
+	}
+
+	fctx = nvme_req(req)->nrq->fctx;
+	nvme_req(req)->nrq->fctx = NULL;
+	blk_mq_start_request(req);
+	nvme_submit_cmd2(nvmeq, &fctx->cmnd, cmnd, write_sq);
+	kfree(fctx);
+	return BLK_STS_OK;
+}
+
 /*
  * NOTE: ns is NULL when called on the admin queue.
  */
@@ -889,6 +944,7 @@ static blk_status_t nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
 	struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
 	struct nvme_command cmnd;
 	blk_status_t ret;
+	int fused;
 
 	iod->aborted = 0;
 	iod->npages = -1;
@@ -917,8 +973,15 @@ static blk_status_t nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
 			goto out_unmap_data;
 	}
 
-	blk_mq_start_request(req);
-	nvme_submit_cmd(nvmeq, &cmnd, bd->last);
+	fused = cmnd.common.flags & (NVME_CMD_FUSE_FIRST|NVME_CMD_FUSE_SECOND);
+	if (likely(!fused)) {
+		blk_mq_start_request(req);
+		nvme_submit_cmd(nvmeq, &cmnd, bd->last);
+	} else {
+		ret = nvme_queue_frq(nvmeq, req, &cmnd, bd->last);
+		if (ret)
+			goto out_unmap_data;
+	}
 	return BLK_STS_OK;
 out_unmap_data:
 	nvme_unmap_data(dev, req);
@@ -2423,6 +2486,22 @@ static void nvme_pci_disable(struct nvme_dev *dev)
 	}
 }
 
+static bool nvme_pci_cancel_rq(struct request *req, void *data, bool reserved)
+{
+	if (unlikely(nvme_req(req)->cmd->common.flags & NVME_CMD_FUSE_FIRST)) {
+		struct nvme_fused_ctx *fctx = nvme_req(req)->fctx;
+
+		/* this will only be set if 2nd fused isn't queued yet */
+		if (unlikely(fctx)) {
+			fctx->nrq2->nrq = NULL;	/* break link of 2nd fused */
+			nvme_req(req)->fctx = NULL;
+			kfree(fctx);
+		}
+	}
+	return nvme_cancel_request(req, data, reserved);
+}
+
+
 static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown)
 {
 	bool dead = true, freeze = false;
@@ -2459,7 +2538,7 @@ static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown)
 	nvme_pci_disable(dev);
 	nvme_reap_pending_cqes(dev);
 
-	blk_mq_tagset_busy_iter(&dev->tagset, nvme_cancel_request, &dev->ctrl);
+	blk_mq_tagset_busy_iter(&dev->tagset, nvme_pci_cancel_rq, &dev->ctrl);
 	blk_mq_tagset_busy_iter(&dev->admin_tagset, nvme_cancel_request, &dev->ctrl);
 	blk_mq_tagset_wait_completed_request(&dev->tagset);
 	blk_mq_tagset_wait_completed_request(&dev->admin_tagset);
-- 
2.27.0



From clay.mayers at kioxia.com  Mon Jan 25 14:58:44 2021
From: clay.mayers at kioxia.com (clay.mayers at kioxia.com)
Date: Mon, 25 Jan 2021 11:58:44 -0800
Subject: [PATCH V2 2/2] nvme: support fused NVME_IOCTL_SUBMIT_IO
In-Reply-To: <20210105224939.1336-2-clay.mayers@kioxia.com>
References: <20210105224939.1336-2-clay.mayers@kioxia.com>
Message-ID: <20210125195844.1390581-3-clay.mayers@kioxia.com>

From: Clay Mayers <clay.mayers at kioxia.com>

Extends the functionality of the NVME_IOCTL_SUBMIT_IO ioctl to support
a pair of fused nvme_user_io requests.

When submitting a fused pair, an array of two nvme_user_io structs are
supplied when invoking NVME_IOCTL_SUBMIT_IO ioctl.  Rather than
introduce a new ioctl code, the presence of a fused pair is indicated
by the nvme_user_io.flags having the value of NVME_CMD_FUSED_FIRST.
This then indicates a second nvme_user_io struct follows the first with
an nvme_user_io.flags set to NVME_CMD_FUSED_SECOND.

A fused pair may fail to submit with -EWOULDBLOCK.  This indicates the
device queue selected for the first command didn't have a tag available
when the request for the second command was created.  The caller should
retry the request.

v2:
Restricted fused support to just the pci transport
Restored the #ifdef CONFIG_COMPAT around nvme_user_io32 defines.

Signed-off-by: Clay Mayers <clay.mayers at kioxia.com>
---
 drivers/nvme/host/core.c | 267 ++++++++++++++++++++++++++++++---------
 1 file changed, 208 insertions(+), 59 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 9a270e49df17..29e9129f6bf3 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -1467,16 +1467,40 @@ static void __user *nvme_to_user_ptr(uintptr_t ptrval)
 	return (void __user *)ptrval;
 }
 
-static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
+struct nvme_user_io_req {
+	struct nvme_command cmd;
+	struct request *rq;
+	struct bio *bio;	/* bio in rq at the time of allocation */
+	void *meta;
+	void __user *udata;
+	void __user *umeta;
+	unsigned int len;
+	unsigned int mlen;
+	u32 mseed;
+};
+
+static void nvme_free_io(struct nvme_user_io_req *nrq)
+{
+	if (!nrq)
+		return;
+	kfree(nrq->meta);
+	if (nrq->bio)
+		blk_rq_unmap_user(nrq->bio);
+	if (nrq->rq)
+		blk_mq_free_request(nrq->rq);
+	nrq->meta = NULL;
+	nrq->bio = NULL;
+	nrq->rq = NULL;
+}
+
+static int nvme_prep_io(struct nvme_ns *ns, struct nvme_user_io_req *nrq,
+			struct nvme_user_io __user *uio, int size)
 {
 	struct nvme_user_io io;
-	struct nvme_command c;
-	unsigned length, meta_len;
-	void __user *metadata;
 
-	if (copy_from_user(&io, uio, sizeof(io)))
+	if (unlikely(copy_from_user(&io, uio, size)))
 		return -EFAULT;
-	if (io.flags)
+	if (unlikely(io.flags & ~(NVME_CMD_FUSE_FIRST|NVME_CMD_FUSE_SECOND)))
 		return -EINVAL;
 
 	switch (io.opcode) {
@@ -1488,33 +1512,165 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
 		return -EINVAL;
 	}
 
-	length = (io.nblocks + 1) << ns->lba_shift;
-	meta_len = (io.nblocks + 1) * ns->ms;
-	metadata = nvme_to_user_ptr(io.metadata);
+	nrq->udata = nvme_to_user_ptr(io.addr);
+	nrq->len = (io.nblocks + 1) << ns->lba_shift;
+	nrq->umeta = nvme_to_user_ptr(io.metadata);
+	nrq->mlen = (io.nblocks + 1) * ns->ms;
+	nrq->mseed = lower_32_bits(io.slba);
+	nrq->bio = nrq->meta = NULL;
 
 	if (ns->features & NVME_NS_EXT_LBAS) {
-		length += meta_len;
-		meta_len = 0;
-	} else if (meta_len) {
+		nrq->len += nrq->mlen;
+		nrq->mlen = 0;
+	} else if (nrq->mlen) {
 		if ((io.metadata & 3) || !io.metadata)
 			return -EINVAL;
 	}
 
-	memset(&c, 0, sizeof(c));
-	c.rw.opcode = io.opcode;
-	c.rw.flags = io.flags;
-	c.rw.nsid = cpu_to_le32(ns->head->ns_id);
-	c.rw.slba = cpu_to_le64(io.slba);
-	c.rw.length = cpu_to_le16(io.nblocks);
-	c.rw.control = cpu_to_le16(io.control);
-	c.rw.dsmgmt = cpu_to_le32(io.dsmgmt);
-	c.rw.reftag = cpu_to_le32(io.reftag);
-	c.rw.apptag = cpu_to_le16(io.apptag);
-	c.rw.appmask = cpu_to_le16(io.appmask);
-
-	return nvme_submit_user_cmd(ns->queue, &c,
-			nvme_to_user_ptr(io.addr), length,
-			metadata, meta_len, lower_32_bits(io.slba), NULL, 0);
+	memset(&nrq->cmd, 0, sizeof(nrq->cmd));
+	nrq->cmd.rw.opcode = io.opcode;
+	nrq->cmd.rw.flags = io.flags;
+	nrq->cmd.rw.nsid = cpu_to_le32(ns->head->ns_id);
+	nrq->cmd.rw.slba = cpu_to_le64(io.slba);
+	nrq->cmd.rw.length = cpu_to_le16(io.nblocks);
+	nrq->cmd.rw.control = cpu_to_le16(io.control);
+	nrq->cmd.rw.dsmgmt = cpu_to_le32(io.dsmgmt);
+	nrq->cmd.rw.reftag = cpu_to_le32(io.reftag);
+	nrq->cmd.rw.apptag = cpu_to_le16(io.apptag);
+	nrq->cmd.rw.appmask = cpu_to_le16(io.appmask);
+
+	return 0;
+}
+
+static struct request *nvme_mk_req_io(struct nvme_ns *ns,
+				      struct nvme_user_io_req *nrq,
+				      blk_mq_req_flags_t flags, int qid,
+				      int timeout)
+{
+	bool write = nvme_is_write(&nrq->cmd);
+	struct request_queue *q = ns->queue;
+	struct gendisk *disk = ns->disk;
+	struct request *rq;
+	struct bio *bio = NULL;
+	void *meta = NULL;
+	int ret;
+
+	rq = nvme_alloc_request(q, &nrq->cmd, flags, qid);
+	if (IS_ERR(rq))
+		return rq;
+
+	rq->timeout = timeout ? timeout : ADMIN_TIMEOUT;
+	nvme_req(rq)->flags |= NVME_REQ_USERCMD;
+
+	if (nrq->udata && nrq->len) {
+		ret = blk_rq_map_user(q, rq, NULL, nrq->udata, nrq->len,
+				GFP_KERNEL);
+		if (ret)
+			goto out;
+		bio = rq->bio;
+		bio->bi_disk = disk;
+		if (disk && nrq->umeta && nrq->mlen) {
+			meta = nvme_add_user_metadata(bio, nrq->umeta, nrq->mlen,
+					nrq->mseed, write);
+			if (IS_ERR(meta)) {
+				ret = PTR_ERR(meta);
+				goto out_unmap;
+			}
+			nrq->meta = meta;
+		}
+	}
+	nrq->bio = bio;
+	return rq;
+out_unmap:
+	if (bio)
+		blk_rq_unmap_user(bio);
+ out:
+	blk_mq_free_request(rq);
+	return ERR_PTR(ret);
+}
+
+static int nvme_unprep_io(struct nvme_user_io_req *nrq,
+			  u64 *result)
+{
+	struct request *rq = nrq->rq;
+	int write = nvme_is_write(&nrq->cmd);
+	int ret;
+
+	if (unlikely(nvme_req(rq)->flags & NVME_REQ_CANCELLED))
+		ret = -EINTR;
+	else
+		ret = nvme_req(rq)->status;
+	if (result)
+		*result = le64_to_cpu(nvme_req(rq)->result.u64);
+	if (nrq->meta && !ret && !write) {
+		if (copy_to_user(nrq->umeta, nrq->meta, nrq->mlen))
+			ret = -EFAULT;
+	}
+	nvme_free_io(nrq);
+	return ret;
+}
+
+/* support both NVME_IOCTL_SUBMIT_IO and NVME_IOCTL_SUBMIT_IO32 */
+static int nvme_submit_io(struct nvme_ns *ns, void __user *uio,
+			  int size)
+{
+	struct nvme_ctrl *ctrl = ns->ctrl;
+	struct nvme_user_io_req nrq, nrq2;
+	struct request *rq, *rq2;
+	int ret, fused;
+
+	ret = nvme_prep_io(ns, &nrq, uio, size);
+	if (unlikely(ret))
+		return ret;
+	fused = (nrq.cmd.common.flags == NVME_CMD_FUSE_FIRST);
+	if (fused) {
+		if (!(ctrl->ops->flags & NVME_F_PCI_P2PDMA))
+			return -EINVAL;
+		ret = nvme_prep_io(ns, &nrq2, uio+size, size);
+		if (unlikely(ret))
+			return ret;
+		if (unlikely(nrq2.cmd.common.flags != NVME_CMD_FUSE_SECOND))
+			return -EINVAL;
+	} else if (unlikely(nrq.cmd.common.flags)) {
+		return -EINVAL;
+	}
+	rq = nvme_mk_req_io(ns, &nrq, 0, NVME_QID_ANY, 0);
+	if (IS_ERR(rq))
+		return PTR_ERR(rq);
+	nrq.rq = rq;
+	if (fused) {
+		DECLARE_COMPLETION_ONSTACK(wait);
+
+		rq2 = nvme_mk_req_io(ns, &nrq2, BLK_MQ_REQ_NOWAIT,
+				     nvme_req_qid(rq), 0);
+		if (IS_ERR(rq2)) {
+			nvme_free_io(&nrq);
+			return PTR_ERR(rq2);
+		}
+		/* point requests at each other */
+		nvme_req(rq)->nrq = nvme_req(rq2);
+		nvme_req(rq2)->nrq = nvme_req(rq);
+		nrq2.rq = rq2;
+
+		rq->cmd_flags |= REQ_NOMERGE;
+		rq2->cmd_flags |= REQ_NOMERGE;
+		rq->end_io_data = &wait;
+		blk_execute_rq_nowait(rq->q, ns->disk, rq, false, nvme_end_sync_rq);
+		nvme_execute_passthru_rq(rq2);
+
+		/*
+		 * both will be complete at this point, but nvme spec doesn't
+		 * specify cqe ordering for fused operations so wait for the
+		 * first to complete as well
+		 */
+		wait_for_completion_io(&wait);
+		nvme_unprep_io(&nrq, NULL);
+		ret = nvme_unprep_io(&nrq2, NULL);
+	} else {
+		nvme_execute_passthru_rq(rq);
+		ret = nvme_unprep_io(&nrq, NULL);
+	}
+	return ret;
 }
 
 static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
@@ -1671,6 +1827,25 @@ static int nvme_handle_ctrl_ioctl(struct nvme_ns *ns, unsigned int cmd,
 	return ret;
 }
 
+#ifdef CONFIG_COMPAT
+struct nvme_user_io32 {
+	__u8	opcode;
+	__u8	flags;
+	__u16	control;
+	__u16	nblocks;
+	__u16	rsvd;
+	__u64	metadata;
+	__u64	addr;
+	__u64	slba;
+	__u32	dsmgmt;
+	__u32	reftag;
+	__u16	apptag;
+	__u16	appmask;
+} __attribute__((__packed__));
+
+#define NVME_IOCTL_SUBMIT_IO32	_IOW('N', 0x42, struct nvme_user_io32)
+#endif
+
 static int nvme_ioctl(struct block_device *bdev, fmode_t mode,
 		unsigned int cmd, unsigned long arg)
 {
@@ -1699,8 +1874,12 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode,
 	case NVME_IOCTL_IO_CMD:
 		ret = nvme_user_cmd(ns->ctrl, ns, argp);
 		break;
+#ifdef CONFIG_COMPAT
+	case NVME_IOCTL_SUBMIT_IO32:
+		fallthrough;	/* structures are identical except size */
+#endif
 	case NVME_IOCTL_SUBMIT_IO:
-		ret = nvme_submit_io(ns, argp);
+		ret = nvme_submit_io(ns, argp, _IOC_SIZE(cmd));
 		break;
 	case NVME_IOCTL_IO64_CMD:
 		ret = nvme_user_cmd64(ns->ctrl, ns, argp);
@@ -1716,41 +1895,11 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode,
 	return ret;
 }
 
-#ifdef CONFIG_COMPAT
-struct nvme_user_io32 {
-	__u8	opcode;
-	__u8	flags;
-	__u16	control;
-	__u16	nblocks;
-	__u16	rsvd;
-	__u64	metadata;
-	__u64	addr;
-	__u64	slba;
-	__u32	dsmgmt;
-	__u32	reftag;
-	__u16	apptag;
-	__u16	appmask;
-} __attribute__((__packed__));
-
-#define NVME_IOCTL_SUBMIT_IO32	_IOW('N', 0x42, struct nvme_user_io32)
 
+#ifdef CONFIG_COMPAT
 static int nvme_compat_ioctl(struct block_device *bdev, fmode_t mode,
 		unsigned int cmd, unsigned long arg)
 {
-	/*
-	 * Corresponds to the difference of NVME_IOCTL_SUBMIT_IO
-	 * between 32 bit programs and 64 bit kernel.
-	 * The cause is that the results of sizeof(struct nvme_user_io),
-	 * which is used to define NVME_IOCTL_SUBMIT_IO,
-	 * are not same between 32 bit compiler and 64 bit compiler.
-	 * NVME_IOCTL_SUBMIT_IO32 is for 64 bit kernel handling
-	 * NVME_IOCTL_SUBMIT_IO issued from 32 bit programs.
-	 * Other IOCTL numbers are same between 32 bit and 64 bit.
-	 * So there is nothing to do regarding to other IOCTL numbers.
-	 */
-	if (cmd == NVME_IOCTL_SUBMIT_IO32)
-		return nvme_ioctl(bdev, mode, NVME_IOCTL_SUBMIT_IO, arg);
-
 	return nvme_ioctl(bdev, mode, cmd, arg);
 }
 #else
-- 
2.27.0



From minwoo.im.dev at gmail.com  Mon Jan 25 19:29:00 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Tue, 26 Jan 2021 09:29:00 +0900
Subject: [PATCH V6 0/1] block: fix I/O errors in BLKRRPART
Message-ID: <20210126002901.5533-1-minwoo.im.dev@gmail.com>

Hello,

(This series is just RESEND with rebasing it on for-next)

  This patch fixes I/O errors during BLKRRPART ioctl() behavior right
after format operation that changed logical block size of the block
device with a same file descriptor opened.

Testcase:

  The following testcase is a case of NVMe namespace with the following
conditions:

  - Current LBA format is lbaf=0 (512 bytes logical block size)
  - LBA Format(lbaf=1) has 4096 bytes logical block size

  # Format block device logical block size 512B to 4096B                                                                                                                                                                                                                                                                                                                                       
  nvme format /dev/nvme0n1 --lbaf=1 --force

  This will cause I/O errors because BLKRRPART ioctl() happened right after
the format command with same file descriptor opened in application
(e.g., nvme-cli) like:

  fd = open("/dev/nvme0n1", O_RDONLY);

  nvme_format(fd, ...);
  if (ioctl(fd, BLKRRPART) < 0)
        ...

Errors:

  We can see the Read command with Number of LBA(NLB) 0xffff(65535) which
was under-flowed because BLKRRPART operation requested request size based
on i_blkbits of the block device which is 9 via buffer_head.

  [dmesg-snip]
    [   10.771740] blk_update_request: operation not supported error, dev nvme0n1, sector 0 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 0
    [   10.780262] Buffer I/O error on dev nvme0n1, logical block 0, async page read

  [event-snip]
    kworker/0:1H-56      [000] ....   913.456922: nvme_setup_cmd: nvme0: disk=nvme0n1, qid=1, cmdid=216, nsid=1, flags=0x0, meta=0x0, cmd=(nvme_cmd_read slba=0, len=65535, ctrl=0x0, dsmgmt=0, reftag=0)
     ksoftirqd/0-9       [000] .Ns.   916.566351: nvme_complete_rq: nvme0: disk=nvme0n1, qid=1, cmdid=216, res=0x0, retries=0, flags=0x0, status=0x4002

  The patch below fixes the I/O errors by rejecting I/O requests from the
block layer with setting a flag to request_queue until the file descriptor
re-opened to be updated by __blkdev_get().  This is based on the previous
discussion [1].

Since V5:
  - Rebased on for-next

Since V4:
  - Rebased on block-5.11.
  - Added Reviewed-by Tag from Christoph.

Since V3(RFC):
  - Move flag from gendisk to request_queue for future clean-ups.
    (Christoph, [3])

Since V2(RFC):
  - Cover letter with testcase and error logs attached. Removed un-related
    changes: empty line. (Chaitanya, [2])
  - Put blkdev with blkdev_put_no_open().

Since V1(RFC):
  - Updated patch to reject I/O rather than updating i_blkbits of the
    block device's inode directly from driver. (Christoph, [1])

Minwoo Im (1):
  block: reject I/O for same fd if block size changed

 block/blk-settings.c    |  3 +++
 block/partitions/core.c | 12 ++++++++++++
 fs/block_dev.c          |  8 ++++++++
 include/linux/blkdev.h  |  1 +
 4 files changed, 24 insertions(+)

-- 
2.17.1



From minwoo.im.dev at gmail.com  Mon Jan 25 19:29:01 2021
From: minwoo.im.dev at gmail.com (Minwoo Im)
Date: Tue, 26 Jan 2021 09:29:01 +0900
Subject: [PATCH V6 1/1] block: reject I/O for same fd if block size changed
In-Reply-To: <20210126002901.5533-1-minwoo.im.dev@gmail.com>
References: <20210126002901.5533-1-minwoo.im.dev@gmail.com>
Message-ID: <20210126002901.5533-2-minwoo.im.dev@gmail.com>

This patch fixes I/O errors during BLKRRPART ioctl() behavior right
after format operation that changed logical block size of the block
device with a same file descriptor opened.

This issue can be easily reproduced with a single format command in case
of NVMe (logical block size 512B to 4096B).

	nvme format /dev/nvme0n1 --lbaf=1 --force

This is because the application, nvme-cli format subcommand issues an
admin command followed by BLKRRPART ioctl to re-read partition
information without closing the file descriptor.  If file descriptor
stays opened, __blkdev_get() will not be invoked at all even logical
block size has been changed.

It will cause I/O errors with invalid Read operations during the
BLKRRPART ioctl due to i_blkbits mismatch. The invalid operations in
BLKRRPART happens with under-flowed Number of LBA(NLB) values
0xffff(65535) because i_blkbits is still set to 9 even the logical block
size has been updated to 4096.  The BLKRRPART will lead buffer_head to
hold 512B data which is less than the logical lock size of the block
device.

The root cause, which is because i_blkbits of inode of the block device
is not updated, can be solved easily by re-opening file descriptor
again from application.  But, that's just for application's business
and kernel should reject invalid Read operations during the BLKRRPART
ioctl.

This patch rejects I/O from the path of add_partitions() to avoid
issuing invalid Read operations to device.  It sets a flag to
request_queue in blk_queue_logical_block_size to minimize caller-side
updates.

Signed-off-by: Minwoo Im <minwoo.im.dev at gmail.com>
Reviewed-by: Christoph Hellwig <hch at lst.de>
---
 block/blk-settings.c    |  3 +++
 block/partitions/core.c | 12 ++++++++++++
 fs/block_dev.c          |  8 ++++++++
 include/linux/blkdev.h  |  1 +
 4 files changed, 24 insertions(+)

diff --git a/block/blk-settings.c b/block/blk-settings.c
index 4c974340f1a9..5b1e0bf54d7e 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -329,6 +329,9 @@ void blk_queue_logical_block_size(struct request_queue *q, unsigned int size)
 {
 	struct queue_limits *limits = &q->limits;
 
+	if (limits->logical_block_size != size)
+		blk_queue_flag_set(QUEUE_FLAG_LBSZ_CHANGED, q);
+
 	limits->logical_block_size = size;
 
 	if (limits->physical_block_size < size)
diff --git a/block/partitions/core.c b/block/partitions/core.c
index b1cdf88f96e2..092d6712c7fc 100644
--- a/block/partitions/core.c
+++ b/block/partitions/core.c
@@ -601,12 +601,24 @@ static bool blk_add_partition(struct gendisk *disk, struct block_device *bdev,
 
 int blk_add_partitions(struct gendisk *disk, struct block_device *bdev)
 {
+	struct request_queue *q = bdev_get_queue(bdev);
 	struct parsed_partitions *state;
 	int ret = -EAGAIN, p;
 
 	if (!disk_part_scan_enabled(disk))
 		return 0;
 
+	/*
+	 * Reject to check partition information if block size has been changed
+	 * in the runtime.  If block size of a block device has been changed,
+	 * the file descriptor should be opened agian to update the blkbits.
+	 */
+	if (test_bit(QUEUE_FLAG_LBSZ_CHANGED, &q->queue_flags)) {
+		pr_warn("%s: rejecting checking partition. fd should be opened again.\n",
+				disk->disk_name);
+		return -EBADFD;
+	}
+
 	state = check_partition(disk, bdev);
 	if (!state)
 		return 0;
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 6f5bd9950baf..8555308c503d 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -130,7 +130,15 @@ EXPORT_SYMBOL(truncate_bdev_range);
 
 static void set_init_blocksize(struct block_device *bdev)
 {
+	struct request_queue *q = bdev_get_queue(bdev);
+
 	bdev->bd_inode->i_blkbits = blksize_bits(bdev_logical_block_size(bdev));
+
+	/*
+	 * Allow I/O commands for this block device.  We can say that this
+	 * block device has proper blkbits updated.
+	 */
+	blk_queue_flag_clear(QUEUE_FLAG_LBSZ_CHANGED, q);
 }
 
 int set_blocksize(struct block_device *bdev, int size)
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 20f3706b6b2e..f725e933db40 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -621,6 +621,7 @@ struct request_queue {
 #define QUEUE_FLAG_RQ_ALLOC_TIME 27	/* record rq->alloc_time_ns */
 #define QUEUE_FLAG_HCTX_ACTIVE	28	/* at least one blk-mq hctx is active */
 #define QUEUE_FLAG_NOWAIT       29	/* device supports NOWAIT */
+#define QUEUE_FLAG_LBSZ_CHANGED	30	/* logical block size changed */
 
 #define QUEUE_FLAG_MQ_DEFAULT	((1 << QUEUE_FLAG_IO_STAT) |		\
 				 (1 << QUEUE_FLAG_SAME_COMP) |		\
-- 
2.17.1



From Chaitanya.Kulkarni at wdc.com  Mon Jan 25 20:43:03 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Tue, 26 Jan 2021 01:43:03 +0000
Subject: [PATCH V2 0/2] nvme: Support for fused NVME_IOCTL_SUBMIT_IO
References: <20210105224939.1336-2-clay.mayers@kioxia.com>
 <20210125195844.1390581-1-clay.mayers@kioxia.com>
Message-ID: <BYAPR04MB49650B6342C736B5268F833686BC9@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/25/21 12:03, clay.mayers at kioxia.com wrote:
> Local pci device fused support is also necessary for
> NVMeOF targets to support fused operation.
Please explain the use case and the application of the NVMeOF
fuse command feature.


From Chaitanya.Kulkarni at wdc.com  Mon Jan 25 21:04:38 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Tue, 26 Jan 2021 02:04:38 +0000
Subject: Problem with SPCC 256GB NVMe 1.3 drive - refcount_t: underflow;
 use-after-free.
References: <f50bc59c-db11-bb44-55be-7b9db1119872@comcast.net>
 <BYAPR04MB49659C0F0F0E11D166B31E0586A40@BYAPR04MB4965.namprd04.prod.outlook.com>
 <a4c75497-d170-1e0f-8608-282231ff3a8e@comcast.net>
 <BYAPR04MB496542BEF594F0380F7D41CF86A20@BYAPR04MB4965.namprd04.prod.outlook.com>
 <df46d7ce-ce70-1f43-0efd-7153761bcff0@comcast.net>
 <20210121124459.GA156577@localhost.localdomain>
 <c48abecf-8e4f-b76a-c751-1a0d239c99b3@comcast.net>
 <BYAPR04MB4965404638B4C43DBA577D1686A00@BYAPR04MB4965.namprd04.prod.outlook.com>
 <BYAPR04MB4965342B52D5C3C6D8A7892D86A00@BYAPR04MB4965.namprd04.prod.outlook.com>
 <23f49172-5d0e-618a-199d-d568f695dc30@comcast.net>
 <20210125081654.GA226984@localhost.localdomain>
 <6709E718-ABD5-4B69-B4E7-883C4E4CD178@wdc.com>
 <05db52bd-7484-56f1-510f-b1bd3808d385@comcast.net>
Message-ID: <BYAPR04MB49655D68A8FD54E1BD6E181286BC9@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/25/21 18:03, Bradley Chapman wrote:
> As Chaitanya pointed out, I did in fact re-test with the correct patch 
> and everything worked flawlessly. I have sent the corrected patches to 
> Chaitanya directly.
>
> Brad
>
Thanks for confirming that, I'll send a patch with your tested by tag.


From chapman6235 at comcast.net  Mon Jan 25 21:03:27 2021
From: chapman6235 at comcast.net (Bradley Chapman)
Date: Mon, 25 Jan 2021 21:03:27 -0500
Subject: Problem with SPCC 256GB NVMe 1.3 drive - refcount_t: underflow;
 use-after-free.
In-Reply-To: <6709E718-ABD5-4B69-B4E7-883C4E4CD178@wdc.com>
References: <f50bc59c-db11-bb44-55be-7b9db1119872@comcast.net>
 <BYAPR04MB49659C0F0F0E11D166B31E0586A40@BYAPR04MB4965.namprd04.prod.outlook.com>
 <a4c75497-d170-1e0f-8608-282231ff3a8e@comcast.net>
 <BYAPR04MB496542BEF594F0380F7D41CF86A20@BYAPR04MB4965.namprd04.prod.outlook.com>
 <df46d7ce-ce70-1f43-0efd-7153761bcff0@comcast.net>
 <20210121124459.GA156577@localhost.localdomain>
 <c48abecf-8e4f-b76a-c751-1a0d239c99b3@comcast.net>
 <BYAPR04MB4965404638B4C43DBA577D1686A00@BYAPR04MB4965.namprd04.prod.outlook.com>
 <BYAPR04MB4965342B52D5C3C6D8A7892D86A00@BYAPR04MB4965.namprd04.prod.outlook.com>
 <23f49172-5d0e-618a-199d-d568f695dc30@comcast.net>
 <20210125081654.GA226984@localhost.localdomain>
 <6709E718-ABD5-4B69-B4E7-883C4E4CD178@wdc.com>
Message-ID: <05db52bd-7484-56f1-510f-b1bd3808d385@comcast.net>

Good evening!

On 1/25/21 3:34 AM, Chaitanya Kulkarni wrote:
> I have pointed that out on friday already offline to reduce the mailing list noise.
> 
>> On Jan 25, 2021, at 12:16 AM, Niklas Cassel <Niklas.Cassel at wdc.com> wrote:
>>
>> ?On Fri, Jan 22, 2021 at 07:54:26PM -0500, Bradley Chapman wrote:
>>> With the following patch applied to the NVMe tree, my system hard-locked and
>>> would not respond to Alt+SysRQ once I mounted the filesystem and attempted a
>>> directory listing of the root of the filesystem.
>>>
>>> diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
>>> index 25456d02eddb..7ba5e8e92e19 100644
>>> --- a/drivers/nvme/host/pci.c
>>> +++ b/drivers/nvme/host/pci.c
>>> @@ -3228,6 +3228,8 @@ static const struct pci_device_id nvme_id_table[] = {
>>>                 .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
>>>         { PCI_DEVICE(0x15b7, 0x2001),   /*  Sandisk Skyhawk */
>>>                 .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
>>> +       { PCI_DEVICE(0x1d97, 0x2263),   /*  SPCC */
>>> +               .driver_data = NVME_QUIRK_SINGLE_VECTOR },
>>>         { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2001),
>>>                 .driver_data = NVME_QUIRK_SINGLE_VECTOR },
>>>         { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2003) },
>>>
>>
>> Hello Bradley,
>>
>> Chaitanya asked you to test the NVME_QUIRK_DISABLE_WRITE_ZEROES quirk.
>> Your patch seems to instead use the NVME_QUIRK_SINGLE_VECTOR quirk.
>>
>> Did you try the NVME_QUIRK_DISABLE_WRITE_ZEROES quirk?
>>
>>
>> Kind regards,
>> Niklas

As Chaitanya pointed out, I did in fact re-test with the correct patch 
and everything worked flawlessly. I have sent the corrected patches to 
Chaitanya directly.

Brad


From chaitanya.kulkarni at wdc.com  Tue Jan 26 00:19:16 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Mon, 25 Jan 2021 21:19:16 -0800
Subject: [PATCH] nvme-pci: add write-zeores SPCC quirk
Message-ID: <20210126051916.3271-1-chaitanya.kulkarni@wdc.com>

This adds a quirk for SPCC 256GB NVMe 1.3 drive which fixes the
following problem :-

[ 2745.659527] CPU: 2 PID: 0 Comm: swapper/2 Tainted: G            E
5.10.6-BET #1
[ 2745.659528] Hardware name: System manufacturer System Product
Name/PRIME X570-P, BIOS 3001 12/04/2020
[ 2776.138874] nvme nvme1: I/O 414 QID 3 timeout, aborting
[ 2776.138886] nvme nvme1: I/O 415 QID 3 timeout, aborting
[ 2776.138891] nvme nvme1: I/O 416 QID 3 timeout, aborting
[ 2776.138895] nvme nvme1: I/O 417 QID 3 timeout, aborting
[ 2776.138912] nvme nvme1: Abort status: 0x0
[ 2776.138921] nvme nvme1: I/O 428 QID 3 timeout, aborting
[ 2776.138922] nvme nvme1: Abort status: 0x0
[ 2776.138925] nvme nvme1: Abort status: 0x0
[ 2776.138974] nvme nvme1: Abort status: 0x0
[ 2776.138977] nvme nvme1: Abort status: 0x0
[ 2806.346792] nvme nvme1: I/O 414 QID 3 timeout, reset controller
[ 2806.363566] nvme nvme1: 15/0/0 default/read/poll queues
[ 2836.554298] nvme nvme1: I/O 415 QID 3 timeout, disable controller
[ 2836.672064] blk_update_request: I/O error, dev nvme1n1, sector 16350
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[ 2836.672072] blk_update_request: I/O error, dev nvme1n1, sector 16093
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[ 2836.672074] blk_update_request: I/O error, dev nvme1n1, sector 15836
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[ 2836.672076] blk_update_request: I/O error, dev nvme1n1, sector 15579
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[ 2836.672078] blk_update_request: I/O error, dev nvme1n1, sector 15322
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[ 2836.672080] blk_update_request: I/O error, dev nvme1n1, sector 15065
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[ 2836.672082] blk_update_request: I/O error, dev nvme1n1, sector 14808
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[ 2836.672083] blk_update_request: I/O error, dev nvme1n1, sector 14551
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[ 2836.672085] blk_update_request: I/O error, dev nvme1n1, sector 14294
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[ 2836.672087] blk_update_request: I/O error, dev nvme1n1, sector 14037
op 0x9:(WRITE_ZEROES) flags 0x0 phys_seg 0 prio class 0
[ 2836.672121] nvme nvme1: failed to mark controller live state
[ 2836.672123] nvme nvme1: Removing after probe failure status: -19
[ 2836.689016] Aborting journal on device dm-0-8.
[ 2836.689024] Buffer I/O error on dev dm-0, logical block 25198592,
lost sync page write
[ 2836.689027] JBD2: Error -5 detected when updating journal superblock
for dm-0-8.

Tested-by: Bradley Chapman <chapman6235 at comcast.net>
Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/host/pci.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 25456d02eddb..0c1e492e0c94 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -3228,6 +3228,8 @@ static const struct pci_device_id nvme_id_table[] = {
 		.driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
 	{ PCI_DEVICE(0x15b7, 0x2001),   /*  Sandisk Skyhawk */
 		.driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
+	{ PCI_DEVICE(0x1d97, 0x2263),   /* SPCC */
+		.driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
 	{ PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2001),
 		.driver_data = NVME_QUIRK_SINGLE_VECTOR },
 	{ PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2003) },
-- 
2.22.1



From lengchao at huawei.com  Tue Jan 26 03:15:39 2021
From: lengchao at huawei.com (Chao Leng)
Date: Tue, 26 Jan 2021 16:15:39 +0800
Subject: [PATCH v4 5/5] nvme-fc: avoid IO error for nvme native multipath
In-Reply-To: <20210126081539.13320-1-lengchao@huawei.com>
References: <20210126081539.13320-1-lengchao@huawei.com>
Message-ID: <20210126081539.13320-6-lengchao@huawei.com>

Work with nvme native multipath, if a path related error occurs when
queue_rq call HBA drive to send request, queue_rq will return
BLK_STS_IOERR to blk-mq. The request is completed with BLK_STS_IOERR
instead of fail over to retry.
queue_rq need call nvme_complete_rq to complete the request with
NVME_SC_HOST_PATH_ERROR, the request will fail over to retry if needed.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 drivers/nvme/host/fc.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c
index 5f36cfa8136c..400a5638d68a 100644
--- a/drivers/nvme/host/fc.c
+++ b/drivers/nvme/host/fc.c
@@ -2791,7 +2791,12 @@ nvme_fc_queue_rq(struct blk_mq_hw_ctx *hctx,
 	}
 
 
-	return nvme_fc_start_fcp_op(ctrl, queue, op, data_len, io_dir);
+	ret = nvme_fc_start_fcp_op(ctrl, queue, op, data_len, io_dir);
+	if (ret == BLK_STS_IOERR) {
+		nvme_complete_failed_rq(rq, NVME_SC_HOST_PATH_ERROR);
+		ret = BLK_STS_OK;
+	}
+	return ret;
 }
 
 static void
-- 
2.16.4



From lengchao at huawei.com  Tue Jan 26 03:15:38 2021
From: lengchao at huawei.com (Chao Leng)
Date: Tue, 26 Jan 2021 16:15:38 +0800
Subject: [PATCH v4 4/5] nvme-rdma: avoid IO error for nvme native multipath
In-Reply-To: <20210126081539.13320-1-lengchao@huawei.com>
References: <20210126081539.13320-1-lengchao@huawei.com>
Message-ID: <20210126081539.13320-5-lengchao@huawei.com>

Work with nvme native multipath, if a path related error occurs when
queue_rq call HBA drive to send request, queue_rq will return
BLK_STS_IOERR to blk-mq. The request is completed with BLK_STS_IOERR
instead of fail over to retry.
queue_rq need call nvme_complete_rq to complete the request with
NVME_SC_HOST_PATH_ERROR, the request will fail over to retry if needed.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 drivers/nvme/host/rdma.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index b7ce4f221d99..7c801132d5ed 100644
--- a/drivers/nvme/host/rdma.c
+++ b/drivers/nvme/host/rdma.c
@@ -2037,6 +2037,7 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
 	bool queue_ready = test_bit(NVME_RDMA_Q_LIVE, &queue->flags);
 	blk_status_t ret;
 	int err;
+	bool driver_error = false;
 
 	WARN_ON_ONCE(rq->tag < 0);
 
@@ -2084,8 +2085,10 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
 
 	err = nvme_rdma_post_send(queue, sqe, req->sge, req->num_sge,
 			req->mr ? &req->reg_wr.wr : NULL);
-	if (unlikely(err))
+	if (unlikely(err)) {
+		driver_error = true;
 		goto err_unmap;
+	}
 
 	return BLK_STS_OK;
 
@@ -2100,6 +2103,10 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
 unmap_qe:
 	ib_dma_unmap_single(dev, req->sqe.dma, sizeof(struct nvme_command),
 			    DMA_TO_DEVICE);
+	if (driver_error && ret == BLK_STS_IOERR) {
+		nvme_complete_failed_rq(rq, NVME_SC_HOST_PATH_ERROR);
+		ret = BLK_STS_OK;
+	}
 	return ret;
 }
 
-- 
2.16.4



From lengchao at huawei.com  Tue Jan 26 03:15:36 2021
From: lengchao at huawei.com (Chao Leng)
Date: Tue, 26 Jan 2021 16:15:36 +0800
Subject: [PATCH v4 2/5] nvme-core: introduce complete failed request
In-Reply-To: <20210126081539.13320-1-lengchao@huawei.com>
References: <20210126081539.13320-1-lengchao@huawei.com>
Message-ID: <20210126081539.13320-3-lengchao@huawei.com>

Work with nvme native multipath, if a path related error occurs when
queue_rq call HBA drive to send request, queue_rq need complete the
request with NVME_SC_HOST_PATH_ERROR, the request will fail over to
retry if needed.
So introduce nvme_complete_failed_req for queue_rq and
nvmf_fail_nonready_command.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 drivers/nvme/host/core.c | 8 ++++++++
 drivers/nvme/host/nvme.h | 1 +
 2 files changed, 9 insertions(+)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 8caf9b34734d..9aad4111d9cd 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -356,6 +356,14 @@ void nvme_complete_rq(struct request *req)
 }
 EXPORT_SYMBOL_GPL(nvme_complete_rq);
 
+void nvme_complete_failed_rq(struct request *req, u16 status)
+{
+	nvme_req(req)->status = status;
+	blk_mq_set_request_complete(req);
+	nvme_complete_rq(req);
+}
+EXPORT_SYMBOL_GPL(nvme_complete_failed_rq);
+
 bool nvme_cancel_request(struct request *req, void *data, bool reserved)
 {
 	dev_dbg_ratelimited(((struct nvme_ctrl *) data)->device,
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 88a6b97247f5..f0f609644309 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -575,6 +575,7 @@ static inline bool nvme_is_aen_req(u16 qid, __u16 command_id)
 }
 
 void nvme_complete_rq(struct request *req);
+void nvme_complete_failed_rq(struct request *req, u16 status);
 bool nvme_cancel_request(struct request *req, void *data, bool reserved);
 bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
 		enum nvme_ctrl_state new_state);
-- 
2.16.4



From lengchao at huawei.com  Tue Jan 26 03:15:37 2021
From: lengchao at huawei.com (Chao Leng)
Date: Tue, 26 Jan 2021 16:15:37 +0800
Subject: [PATCH v4 3/5] nvme-fabrics: avoid double request completion for
 nvmf_fail_nonready_command
In-Reply-To: <20210126081539.13320-1-lengchao@huawei.com>
References: <20210126081539.13320-1-lengchao@huawei.com>
Message-ID: <20210126081539.13320-4-lengchao@huawei.com>

When reconnect, the request may be completed with NVME_SC_HOST_PATH_ERROR
in nvmf_fail_nonready_command. The state of request will be changed to
MQ_RQ_IN_FLIGHT before call nvme_complete_rq. If free the request
asynchronously such as in nvme_submit_user_cmd, in extreme scenario
the request may be completed again in tear down process.
nvmf_fail_nonready_command do not need calling blk_mq_start_request
before complete the request. nvmf_fail_nonready_command should set
the state of request to MQ_RQ_COMPLETE before complete the request.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 drivers/nvme/host/fabrics.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c
index 72ac00173500..40f40c0debc1 100644
--- a/drivers/nvme/host/fabrics.c
+++ b/drivers/nvme/host/fabrics.c
@@ -553,9 +553,7 @@ blk_status_t nvmf_fail_nonready_command(struct nvme_ctrl *ctrl,
 	    !blk_noretry_request(rq) && !(rq->cmd_flags & REQ_NVME_MPATH))
 		return BLK_STS_RESOURCE;
 
-	nvme_req(rq)->status = NVME_SC_HOST_PATH_ERROR;
-	blk_mq_start_request(rq);
-	nvme_complete_rq(rq);
+	nvme_complete_failed_rq(rq, NVME_SC_HOST_PATH_ERROR);
 	return BLK_STS_OK;
 }
 EXPORT_SYMBOL_GPL(nvmf_fail_nonready_command);
-- 
2.16.4



From lengchao at huawei.com  Tue Jan 26 03:15:34 2021
From: lengchao at huawei.com (Chao Leng)
Date: Tue, 26 Jan 2021 16:15:34 +0800
Subject: [PATCH v4 0/5] avoid double request completion and IO error
Message-ID: <20210126081539.13320-1-lengchao@huawei.com>

Add blk_mq_set_request_complete and nvme_complete_failed_req for two bug
fixs.
First avoid double request completion for nvmf_fail_nonready_command.
Second avoid IO error for nvme native multipath.

V4:
	- add status parameter for nvme_complete_failed_req.
	- export nvme_complete_failed_req instead of inline function.
V3:
	- complete the request just for HBA driver path related error.
V2:
	- use "switch" instead "if" to check return status.

Chao Leng (5):
  blk-mq: introduce blk_mq_set_request_complete
  nvme-core: introduce complete failed request
  nvme-fabrics: avoid double request completion for
    nvmf_fail_nonready_command
  nvme-rdma: avoid IO error for nvme native multipath
  nvme-fc: avoid IO error for nvme native multipath

 drivers/nvme/host/core.c    | 8 ++++++++
 drivers/nvme/host/fabrics.c | 4 +---
 drivers/nvme/host/fc.c      | 7 ++++++-
 drivers/nvme/host/nvme.h    | 1 +
 drivers/nvme/host/rdma.c    | 9 ++++++++-
 include/linux/blk-mq.h      | 5 +++++
 6 files changed, 29 insertions(+), 5 deletions(-)

-- 
2.16.4



From lengchao at huawei.com  Tue Jan 26 03:15:35 2021
From: lengchao at huawei.com (Chao Leng)
Date: Tue, 26 Jan 2021 16:15:35 +0800
Subject: [PATCH v4 1/5] blk-mq: introduce blk_mq_set_request_complete
In-Reply-To: <20210126081539.13320-1-lengchao@huawei.com>
References: <20210126081539.13320-1-lengchao@huawei.com>
Message-ID: <20210126081539.13320-2-lengchao@huawei.com>

nvme drivers need to set the state of request to MQ_RQ_COMPLETE when
directly complete request in queue_rq.
So add blk_mq_set_request_complete.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 include/linux/blk-mq.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h
index 47b021952ac7..fc096b04bb7a 100644
--- a/include/linux/blk-mq.h
+++ b/include/linux/blk-mq.h
@@ -494,6 +494,11 @@ static inline int blk_mq_request_completed(struct request *rq)
 	return blk_mq_rq_state(rq) == MQ_RQ_COMPLETE;
 }
 
+static inline void blk_mq_set_request_complete(struct request *rq)
+{
+	WRITE_ONCE(rq->state, MQ_RQ_COMPLETE);
+}
+
 void blk_mq_start_request(struct request *rq);
 void blk_mq_end_request(struct request *rq, blk_status_t error);
 void __blk_mq_end_request(struct request *rq, blk_status_t error);
-- 
2.16.4



From martin.wilck at suse.com  Tue Jan 26 06:41:16 2021
From: martin.wilck at suse.com (Martin Wilck)
Date: Tue, 26 Jan 2021 11:41:16 +0000
Subject: RFC: nvme-cli: add "nvme monitor" subcommand
Message-ID: <79bd830da01238e1b36dd8e858e7cc29fcbf2876.camel@suse.com>

Dear all,

I've been working on a small daemon for monitoring and acting on 
NVMe discovery-related events. While pondering over various recent
issues, it occured to me that this might be useful:

Currently it handles only AENs and NVME-FC uevents, but it can be
extended to other protocols in the future.

Following the "publish early" principle, I'm posting this here now.
My test results were positive so far.

I've created a github PR with all the details here, please have a look:

https://github.com/linux-nvme/nvme-cli/pull/877

Issues with the CI came up after I submitted this, I'm working on that.

Feedback would be highly appreciated.

Regards,
Martin

-- 
Dr. Martin Wilck <mwilck at suse.com>, Tel.?+49 (0)911 74053 2107
SUSE Software Solutions Germany GmbH
HRB 36809, AG N?rnberg GF: Felix Imend?rffer




From donnie at sihovision.com  Tue Jan 26 06:17:52 2021
From: donnie at sihovision.com (donnie at sihovision.com)
Date: Tue, 26 Jan 2021 19:17:52 +0800
Subject: Front IP65 Embedded Industrial Touch Monitor
In-Reply-To: <2021010026191700520221@tradepro.net>
Message-ID: <2021010026191700520221@tradepro.net>

Hello,
Sihovision launched a new tyep durable Embedded Industrial Touch Screen Monitor:
Front IP65 waterproof, fully dustproof ,shock proof 
Anti-electromagnetic interference,anti-static, anti surge
Size options: 7'', 8'', 10.1'', 10.4'', 11.6'', 12'', 15'', 15.6'', 17'', 17.3'', 19'', 21.5''
Do you need more specs and quotation for reference? 
------------------------------------------------------------------------
Best regards,
Donnie Nie
SHINHO ELECTRONIC
www.sihovision.com
TEL/Whatsapp: 0086 13163734006
Skype: donnie.shinho
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.infradead.org/pipermail/linux-nvme/attachments/20210126/78c89665/attachment-0001.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: SL700M-1.jpg
Type: image/jpeg
Size: 33868 bytes
Desc: Photo
URL: <http://lists.infradead.org/pipermail/linux-nvme/attachments/20210126/78c89665/attachment-0006.jpg>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: SL700M-2.jpg
Type: image/jpeg
Size: 35170 bytes
Desc: Photo
URL: <http://lists.infradead.org/pipermail/linux-nvme/attachments/20210126/78c89665/attachment-0007.jpg>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: SL700M-3.jpg
Type: image/jpeg
Size: 30491 bytes
Desc: Photo
URL: <http://lists.infradead.org/pipermail/linux-nvme/attachments/20210126/78c89665/attachment-0008.jpg>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: SL700M-4.jpg
Type: image/jpeg
Size: 31279 bytes
Desc: Photo
URL: <http://lists.infradead.org/pipermail/linux-nvme/attachments/20210126/78c89665/attachment-0009.jpg>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: SL700M-5.jpg
Type: image/jpeg
Size: 17113 bytes
Desc: Photo
URL: <http://lists.infradead.org/pipermail/linux-nvme/attachments/20210126/78c89665/attachment-0010.jpg>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: logo2.jpg
Type: image/jpeg
Size: 2231 bytes
Desc: Photo
URL: <http://lists.infradead.org/pipermail/linux-nvme/attachments/20210126/78c89665/attachment-0011.jpg>

From hch at lst.de  Tue Jan 26 09:33:05 2021
From: hch at lst.de (Christoph Hellwig)
Date: Tue, 26 Jan 2021 15:33:05 +0100
Subject: additional ->bi_bdev fixups
Message-ID: <20210126143308.1960860-1-hch@lst.de>

Hi Jens,

more fixes for the (so far theoretical) fallout from the ->bi_bdev
conversion.


From hch at lst.de  Tue Jan 26 09:33:06 2021
From: hch at lst.de (Christoph Hellwig)
Date: Tue, 26 Jan 2021 15:33:06 +0100
Subject: [PATCH 1/3] nvme: use bio_set_dev to assign ->bi_bdev
In-Reply-To: <20210126143308.1960860-1-hch@lst.de>
References: <20210126143308.1960860-1-hch@lst.de>
Message-ID: <20210126143308.1960860-2-hch@lst.de>

Always use the bio_set_dev helper to assign ->bi_bdev to make sure
other state related to the device is uptodate.

Signed-off-by: Christoph Hellwig <hch at lst.de>
---
 drivers/nvme/host/core.c      | 2 +-
 drivers/nvme/host/lightnvm.c  | 2 +-
 drivers/nvme/host/multipath.c | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index eb7963fb167b56..ba5df80881ea98 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -1133,7 +1133,7 @@ static int nvme_submit_user_cmd(struct request_queue *q,
 		if (ret)
 			goto out;
 		bio = req->bio;
-		bio->bi_bdev = bdev;
+		bio_set_dev(bio, bdev);
 		if (bdev && meta_buffer && meta_len) {
 			meta = nvme_add_user_metadata(bio, meta_buffer, meta_len,
 					meta_seed, write);
diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index ec38128f51e994..b705988629f224 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -816,7 +816,7 @@ static int nvme_nvm_submit_user_cmd(struct request_queue *q,
 			vcmd->ph_rw.metadata = cpu_to_le64(metadata_dma);
 		}
 
-		bio->bi_bdev = ns->disk->part0;
+		bio_set_dev(bio, ns->disk->part0);
 	}
 
 	blk_execute_rq(NULL, rq, 0);
diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
index a6d44e7a775f54..65bd6efa5e1c69 100644
--- a/drivers/nvme/host/multipath.c
+++ b/drivers/nvme/host/multipath.c
@@ -312,7 +312,7 @@ blk_qc_t nvme_ns_head_submit_bio(struct bio *bio)
 	srcu_idx = srcu_read_lock(&head->srcu);
 	ns = nvme_find_path(head);
 	if (likely(ns)) {
-		bio->bi_bdev = ns->disk->part0;
+		bio_set_dev(bio, ns->disk->part0);
 		bio->bi_opf |= REQ_NVME_MPATH;
 		trace_block_bio_remap(bio, disk_devt(ns->head->disk),
 				      bio->bi_iter.bi_sector);
@@ -352,7 +352,7 @@ static void nvme_requeue_work(struct work_struct *work)
 		 * Reset disk to the mpath node and resubmit to select a new
 		 * path.
 		 */
-		bio->bi_bdev = head->disk->part0;
+		bio_set_dev(bio, head->disk->part0);
 		submit_bio_noacct(bio);
 	}
 }
-- 
2.29.2



From hch at lst.de  Tue Jan 26 09:33:07 2021
From: hch at lst.de (Christoph Hellwig)
Date: Tue, 26 Jan 2021 15:33:07 +0100
Subject: [PATCH 2/3] bcache: use bio_set_dev to assign ->bi_bdev
In-Reply-To: <20210126143308.1960860-1-hch@lst.de>
References: <20210126143308.1960860-1-hch@lst.de>
Message-ID: <20210126143308.1960860-3-hch@lst.de>

Always use the bio_set_dev helper to assign ->bi_bdev to make sure
other state related to the device is uptodate.

Signed-off-by: Christoph Hellwig <hch at lst.de>
---
 drivers/md/bcache/debug.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/md/bcache/debug.c b/drivers/md/bcache/debug.c
index 058dd80144281e..63e809f38e3f51 100644
--- a/drivers/md/bcache/debug.c
+++ b/drivers/md/bcache/debug.c
@@ -114,7 +114,7 @@ void bch_data_verify(struct cached_dev *dc, struct bio *bio)
 	check = bio_kmalloc(GFP_NOIO, bio_segments(bio));
 	if (!check)
 		return;
-	check->bi_bdev = bio->bi_bdev;
+	bio_set_dev(check, bio->bi_bdev);
 	check->bi_opf = REQ_OP_READ;
 	check->bi_iter.bi_sector = bio->bi_iter.bi_sector;
 	check->bi_iter.bi_size = bio->bi_iter.bi_size;
-- 
2.29.2



From hch at lst.de  Tue Jan 26 09:33:08 2021
From: hch at lst.de (Christoph Hellwig)
Date: Tue, 26 Jan 2021 15:33:08 +0100
Subject: [PATCH 3/3] block: inherit BIO_REMAPPED when cloning bios
In-Reply-To: <20210126143308.1960860-1-hch@lst.de>
References: <20210126143308.1960860-1-hch@lst.de>
Message-ID: <20210126143308.1960860-4-hch@lst.de>

Cloned bios are can be used to on the same device, in which case we need
to inherit the BIO_REMAPPED flag to avoid a double partition remap.  When
the cloned bios are used on another device, bio_set_dev will clear the flag.

Fixes: 309dca309fc3 ("block: store a block_device pointer in struct bio")
Signed-off-by: Christoph Hellwig <hch at lst.de>
---
 block/bio.c                 | 2 ++
 block/blk-crypto-fallback.c | 2 ++
 block/bounce.c              | 2 ++
 3 files changed, 6 insertions(+)

diff --git a/block/bio.c b/block/bio.c
index 99040a7e6656a1..dfd7740a32300a 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -666,6 +666,8 @@ void __bio_clone_fast(struct bio *bio, struct bio *bio_src)
 	bio_set_flag(bio, BIO_CLONED);
 	if (bio_flagged(bio_src, BIO_THROTTLED))
 		bio_set_flag(bio, BIO_THROTTLED);
+	if (bio_flagged(bio_src, BIO_REMAPPED))
+		bio_set_flag(bio, BIO_REMAPPED);
 	bio->bi_opf = bio_src->bi_opf;
 	bio->bi_ioprio = bio_src->bi_ioprio;
 	bio->bi_write_hint = bio_src->bi_write_hint;
diff --git a/block/blk-crypto-fallback.c b/block/blk-crypto-fallback.c
index 8f1e1817673115..50c225398e4d60 100644
--- a/block/blk-crypto-fallback.c
+++ b/block/blk-crypto-fallback.c
@@ -168,6 +168,8 @@ static struct bio *blk_crypto_clone_bio(struct bio *bio_src)
 	if (!bio)
 		return NULL;
 	bio->bi_bdev		= bio_src->bi_bdev;
+	if (bio_flagged(bio_src, BIO_REMAPPED))
+		bio_set_flag(bio, BIO_REMAPPED);
 	bio->bi_opf		= bio_src->bi_opf;
 	bio->bi_ioprio		= bio_src->bi_ioprio;
 	bio->bi_write_hint	= bio_src->bi_write_hint;
diff --git a/block/bounce.c b/block/bounce.c
index a22a8a1942b24f..fc55314aa4269a 100644
--- a/block/bounce.c
+++ b/block/bounce.c
@@ -247,6 +247,8 @@ static struct bio *bounce_clone_bio(struct bio *bio_src, gfp_t gfp_mask,
 	if (!bio)
 		return NULL;
 	bio->bi_bdev		= bio_src->bi_bdev;
+	if (bio_flagged(bio_src, BIO_REMAPPED))
+		bio_set_flag(bio, BIO_REMAPPED);
 	bio->bi_opf		= bio_src->bi_opf;
 	bio->bi_ioprio		= bio_src->bi_ioprio;
 	bio->bi_write_hint	= bio_src->bi_write_hint;
-- 
2.29.2



From hare at suse.de  Tue Jan 26 10:25:11 2021
From: hare at suse.de (Hannes Reinecke)
Date: Tue, 26 Jan 2021 16:25:11 +0100
Subject: [PATCH] nvme: do not ignore nvme status in nvme_set_queue_count()
In-Reply-To: <20210122164454.GA4392@redsun51.ssa.fujisawa.hgst.com>
References: <20210121095021.22807-1-hare@suse.de>
 <20210121201459.GA1727271@dhcp-10-100-145-180.wdc.com>
 <f374b032-cd26-4552-b613-228449f4971d@suse.de>
 <20210122164454.GA4392@redsun51.ssa.fujisawa.hgst.com>
Message-ID: <b27ba758-7635-4235-cb32-d485a01e59f5@suse.de>

On 1/22/21 5:44 PM, Keith Busch wrote:
> On Fri, Jan 22, 2021 at 05:35:35PM +0100, Hannes Reinecke wrote:
>> On 1/21/21 9:14 PM, Keith Busch wrote:
>>> On Thu, Jan 21, 2021 at 10:50:21AM +0100, Hannes Reinecke wrote:
>>>> If the call to nvme_set_queue_count() fails with a status we should
>>>> not ignore it but rather pass it on to the caller.
>>>> It's then up to the transport to decide whether to ignore it
>>>> (like PCI does) or to reset the connection (as would be appropriate
>>>> for fabrics).
>>>
>>> Instead of checking the error, wouldn't checking the number of created
>>> queues be sufficient? What handling difference do you expect to occur
>>> between getting a success with 0 queues, vs getting an error?
>>>
>> The difference is that an error will (re-)start recovery, 0 queues won't.
>> But the problem here is that nvme_set_queue_count() is being called during
>> reconnection, ie during the recovery process itself.
>> And this command is returned with a timeout, which in any other case is
>> being treated as a fatal error. Plus we have been sending this command on
>> the admin queue, so a timeout on the admin queue pretty much _is_  a fatal
>> error. So we should be terminating the current recovery and reconnect. None
>> of that will happen if we return '0' queues.
> 
> You should already be getting an error return status if a timeout occurs
> for nvme_set_queue_count(), specifically -EINTR. Are you getting success
> for some reason?
> 
-EINTR (which translates to 'nvme_req(req)->flags & NVME_REQ_CANCELLED') 
will only ever be returned on pci; fabrics doesn't set this flag, so 
we're never getting an -EINTR.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare at suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 N?rnberg
HRB 36809 (AG N?rnberg), Gesch?ftsf?hrer: Felix Imend?rffer


From elad.grupi at dell.com  Tue Jan 26 10:37:57 2021
From: elad.grupi at dell.com (elad.grupi at dell.com)
Date: Tue, 26 Jan 2021 17:37:57 +0200
Subject: [PATCH] nvme-tcp: proper handling of tcp socket closing flows
Message-ID: <20210126153757.99451-1-elad.grupi@dell.com>

From: Elad Grupi <elad.grupi at dell.com>

avoid calling nvmet_tcp_release_queue_work if tcp socket was closed
before setting the sk callbacks.

prevent io_work from enqueuing while closing the tcp queue to
avoid race with nvmet_tcp_release_queue_work.

Signed-off-by: Elad Grupi <elad.grupi at dell.com>
---
 drivers/nvme/target/tcp.c | 26 +++++++++++++++++++++-----
 1 file changed, 21 insertions(+), 5 deletions(-)

diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
index d535080b781f..937f2a746d8b 100644
--- a/drivers/nvme/target/tcp.c
+++ b/drivers/nvme/target/tcp.c
@@ -647,7 +647,7 @@ static int nvmet_tcp_try_send_one(struct nvmet_tcp_queue *queue,
 	struct nvmet_tcp_cmd *cmd = queue->snd_cmd;
 	int ret = 0;
 
-	if (!cmd || queue->state == NVMET_TCP_Q_DISCONNECTING) {
+	if (!cmd) {
 		cmd = nvmet_tcp_fetch_cmd(queue);
 		if (unlikely(!cmd))
 			return 0;
@@ -1196,7 +1196,7 @@ static void nvmet_tcp_io_work(struct work_struct *w)
 	/*
 	 * We exahusted our budget, requeue our selves
 	 */
-	if (pending)
+	if (pending && queue->state != NVMET_TCP_Q_DISCONNECTING)
 		queue_work_on(queue->cpu, nvmet_tcp_wq, &queue->io_work);
 }
 
@@ -1453,9 +1453,27 @@ static int nvmet_tcp_set_queue_sock(struct nvmet_tcp_queue *queue)
 	sock->sk->sk_state_change = nvmet_tcp_state_change;
 	queue->write_space = sock->sk->sk_write_space;
 	sock->sk->sk_write_space = nvmet_tcp_write_space;
+
+	switch (sk->sk_state) {
+	case TCP_FIN_WAIT1:
+	case TCP_CLOSE_WAIT:
+	case TCP_CLOSE:
+		/* FALLTHRU */
+		sock->sk->sk_data_ready =  queue->data_ready;
+		sock->sk->sk_state_change = queue->state_change;
+		sock->sk->sk_write_space = queue->write_space;
+		sk->sk_user_data = NULL;
+		queue->state = NVMET_TCP_Q_DISCONNECTING;
+		ret = -ENOTCONN;
+		break;
+	default:
+		queue_work_on(queue->cpu, nvmet_tcp_wq, &queue->io_work);
+		ret = 0;
+	}
+
 	write_unlock_bh(&sock->sk->sk_callback_lock);
 
-	return 0;
+	return ret;
 }
 
 static int nvmet_tcp_alloc_queue(struct nvmet_tcp_port *port,
@@ -1506,8 +1524,6 @@ static int nvmet_tcp_alloc_queue(struct nvmet_tcp_port *port,
 	if (ret)
 		goto out_destroy_sq;
 
-	queue_work_on(queue->cpu, nvmet_tcp_wq, &queue->io_work);
-
 	return 0;
 out_destroy_sq:
 	mutex_lock(&nvmet_tcp_queue_mutex);
-- 
2.16.5



From axboe at kernel.dk  Tue Jan 26 10:50:11 2021
From: axboe at kernel.dk (Jens Axboe)
Date: Tue, 26 Jan 2021 08:50:11 -0700
Subject: additional ->bi_bdev fixups
In-Reply-To: <20210126143308.1960860-1-hch@lst.de>
References: <20210126143308.1960860-1-hch@lst.de>
Message-ID: <b33aeb19-094e-c32a-2da0-33cff6f9e418@kernel.dk>

On 1/26/21 7:33 AM, Christoph Hellwig wrote:
> Hi Jens,
> 
> more fixes for the (so far theoretical) fallout from the ->bi_bdev
> conversion.

Applied, thanks.

-- 
Jens Axboe



From johannes.thumshirn at wdc.com  Tue Jan 26 12:50:00 2021
From: johannes.thumshirn at wdc.com (Johannes Thumshirn)
Date: Wed, 27 Jan 2021 02:50:00 +0900
Subject: [PATCH] nvme: add tracing of zns commands
Message-ID: <46eeed2fcf2530d02fe5727a0a91a6e4675f6edd.1611683161.git.johannes.thumshirn@wdc.com>

When support for the NVMe ZNS commands was merged, tracing of these has
been omitted.

Add nvme_cmd_zone_mgmt_send, nvme_cmd_zone_mgmt_recv as well as
nvme_cmd_zone_append to the nvme driver's tracing facility.

Signed-off-by: Johannes Thumshirn <johannes.thumshirn at wdc.com>
---
 drivers/nvme/host/trace.c | 34 ++++++++++++++++++++++++++++++++++
 include/linux/nvme.h      |  6 +++++-
 2 files changed, 39 insertions(+), 1 deletion(-)

diff --git a/drivers/nvme/host/trace.c b/drivers/nvme/host/trace.c
index 5c3cb6928f3c..9f9b6108de7d 100644
--- a/drivers/nvme/host/trace.c
+++ b/drivers/nvme/host/trace.c
@@ -131,6 +131,35 @@ static const char *nvme_trace_dsm(struct trace_seq *p, u8 *cdw10)
 	return ret;
 }
 
+static const char *nvme_trace_zone_mgmt_send(struct trace_seq *p, u8 *cdw10)
+{
+	const char *ret = trace_seq_buffer_ptr(p);
+	u64 slba = get_unaligned_le64(cdw10);
+	u8 zsa = cdw10[12];
+	u8 all = cdw10[13];
+
+	trace_seq_printf(p, "slba=%llu, zsa=%u, all=%u", slba, zsa, all);
+	trace_seq_putc(p, 0);
+
+	return ret;
+}
+
+static const char *nvme_trace_zone_mgmt_recv(struct trace_seq *p, u8 *cdw10)
+{
+	const char *ret = trace_seq_buffer_ptr(p);
+	u64 slba = get_unaligned_le64(cdw10);
+	u32 numd = get_unaligned_le32(cdw10 + 8);
+	u8 zra = cdw10[12];
+	u8 zrasf = cdw10[13];
+	u8 pr = cdw10[14];
+
+	trace_seq_printf(p, "slba=%llu, numd=%u, zra=%u, zrasf=%u, pr=%u",
+			 slba, numd, zra, zrasf, pr);
+	trace_seq_putc(p, 0);
+
+	return ret;
+}
+
 static const char *nvme_trace_common(struct trace_seq *p, u8 *cdw10)
 {
 	const char *ret = trace_seq_buffer_ptr(p);
@@ -171,9 +200,14 @@ const char *nvme_trace_parse_nvm_cmd(struct trace_seq *p,
 	case nvme_cmd_read:
 	case nvme_cmd_write:
 	case nvme_cmd_write_zeroes:
+	case nvme_cmd_zone_append:
 		return nvme_trace_read_write(p, cdw10);
 	case nvme_cmd_dsm:
 		return nvme_trace_dsm(p, cdw10);
+	case nvme_cmd_zone_mgmt_send:
+		return nvme_trace_zone_mgmt_send(p, cdw10);
+	case nvme_cmd_zone_mgmt_recv:
+		return nvme_trace_zone_mgmt_recv(p, cdw10);
 	default:
 		return nvme_trace_common(p, cdw10);
 	}
diff --git a/include/linux/nvme.h b/include/linux/nvme.h
index bfed36e342cc..325dcdd221de 100644
--- a/include/linux/nvme.h
+++ b/include/linux/nvme.h
@@ -697,7 +697,11 @@ enum nvme_opcode {
 		nvme_opcode_name(nvme_cmd_resv_register),	\
 		nvme_opcode_name(nvme_cmd_resv_report),		\
 		nvme_opcode_name(nvme_cmd_resv_acquire),	\
-		nvme_opcode_name(nvme_cmd_resv_release))
+		nvme_opcode_name(nvme_cmd_resv_release),	\
+		nvme_opcode_name(nvme_cmd_zone_mgmt_send),	\
+		nvme_opcode_name(nvme_cmd_zone_mgmt_recv),	\
+		nvme_opcode_name(nvme_cmd_zone_append))
+
 
 
 /*
-- 
2.26.2



From Clay.Mayers at kioxia.com  Tue Jan 26 13:17:06 2021
From: Clay.Mayers at kioxia.com (Clay Mayers)
Date: Tue, 26 Jan 2021 18:17:06 +0000
Subject: [PATCH V2 0/2] nvme: Support for fused NVME_IOCTL_SUBMIT_IO
In-Reply-To: <BYAPR04MB49650B6342C736B5268F833686BC9@BYAPR04MB4965.namprd04.prod.outlook.com>
References: <20210105224939.1336-2-clay.mayers@kioxia.com>
 <20210125195844.1390581-1-clay.mayers@kioxia.com>
 <BYAPR04MB49650B6342C736B5268F833686BC9@BYAPR04MB4965.namprd04.prod.outlook.com>
Message-ID: <b5c179e3eb904800931712d6b92cfbeb@kioxia.com>

> From: Chaitanya Kulkarni <Chaitanya.Kulkarni at wdc.com>
> Sent: Monday, January 25, 2021 5:43 PM
> To: Clay Mayers <Clay.Mayers at kioxia.com>; linux-nvme at lists.infradead.org
> Cc: Keith Busch <kbusch at kernel.org>; Jens Axboe <axboe at fb.com>;
> Christoph Hellwig <hch at lst.de>; Sagi Grimberg <sagi at grimberg.me>
> Subject: Re: [PATCH V2 0/2] nvme: Support for fused
> NVME_IOCTL_SUBMIT_IO
> 
> On 1/25/21 12:03, clay.mayers at kioxia.com wrote:
> > Local pci device fused support is also necessary for NVMeOF targets to
> > support fused operation.
> Please explain the use case and the application of the NVMeOF fuse
> command feature.

NVMeOF devices are used to create disaggregated storage systems
where compute and storage are connected over a fabric.  Fused
compare/write can be used to arbitrate shared access to NVMeOF devices
w/o a central authority.

A specific example of how fused compare/write is used is the clustered
file system VMFS.  It uses the SCSI version of compare/write to manage
meta data on shared SAN systems.  File system meta data is updated
using locks stored on the storage media.  Those locks are grabbed using
fused compare/write operations as an atomic test & set.  VMFS originally
used device reserve, which is a courser gained locking mechanism but it
doesn't scale as well as an atomic test & set.



From Chaitanya.Kulkarni at wdc.com  Tue Jan 26 14:00:59 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Tue, 26 Jan 2021 19:00:59 +0000
Subject: [PATCH V2 0/2] nvme: Support for fused NVME_IOCTL_SUBMIT_IO
References: <20210105224939.1336-2-clay.mayers@kioxia.com>
 <20210125195844.1390581-1-clay.mayers@kioxia.com>
 <BYAPR04MB49650B6342C736B5268F833686BC9@BYAPR04MB4965.namprd04.prod.outlook.com>
 <b5c179e3eb904800931712d6b92cfbeb@kioxia.com>
Message-ID: <BYAPR04MB49652EA8F4CF06D41C708E2386BC9@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/26/21 10:17 AM, Clay Mayers wrote:
>> From: Chaitanya Kulkarni <Chaitanya.Kulkarni at wdc.com>
>> Sent: Monday, January 25, 2021 5:43 PM
>> To: Clay Mayers <Clay.Mayers at kioxia.com>; linux-nvme at lists.infradead.org
>> Cc: Keith Busch <kbusch at kernel.org>; Jens Axboe <axboe at fb.com>;
>> Christoph Hellwig <hch at lst.de>; Sagi Grimberg <sagi at grimberg.me>
>> Subject: Re: [PATCH V2 0/2] nvme: Support for fused
>> NVME_IOCTL_SUBMIT_IO
>>
>> On 1/25/21 12:03, clay.mayers at kioxia.com wrote:
>>> Local pci device fused support is also necessary for NVMeOF targets to
>>> support fused operation.
>> Please explain the use case and the application of the NVMeOF fuse
>> command feature.
> NVMeOF devices are used to create disaggregated storage systems
> where compute and storage are connected over a fabric.  Fused
> compare/write can be used to arbitrate shared access to NVMeOF devices
> w/o a central authority.
>
> A specific example of how fused compare/write is used is the clustered
> file system VMFS.  It uses the SCSI version of compare/write to manage
> meta data on shared SAN systems.  File system meta data is updated
> using locks stored on the storage media.  Those locks are grabbed using
> fused compare/write operations as an atomic test & set.  VMFS originally
> used device reserve, which is a courser gained locking mechanism but it
> doesn't scale as well as an atomic test & set.
If I understand correctly VMFS is out of tree filesystem is it ?
Can you please explain the setup in detail ? what kind of interface
file-system is using to issue the command ?


Based on your description it looks like target is connected to the
vmware based system and host is vmware based host and not the linux
host which is present in this series.
Also what are other applications or is this the only one application?
>



From kbusch at kernel.org  Tue Jan 26 14:06:54 2021
From: kbusch at kernel.org (Keith Busch)
Date: Tue, 26 Jan 2021 11:06:54 -0800
Subject: [PATCH] nvme: do not ignore nvme status in nvme_set_queue_count()
In-Reply-To: <b27ba758-7635-4235-cb32-d485a01e59f5@suse.de>
References: <20210121095021.22807-1-hare@suse.de>
 <20210121201459.GA1727271@dhcp-10-100-145-180.wdc.com>
 <f374b032-cd26-4552-b613-228449f4971d@suse.de>
 <20210122164454.GA4392@redsun51.ssa.fujisawa.hgst.com>
 <b27ba758-7635-4235-cb32-d485a01e59f5@suse.de>
Message-ID: <20210126190654.GB1742960@dhcp-10-100-145-180.wdc.com>

On Tue, Jan 26, 2021 at 04:25:11PM +0100, Hannes Reinecke wrote:
> On 1/22/21 5:44 PM, Keith Busch wrote:
> > On Fri, Jan 22, 2021 at 05:35:35PM +0100, Hannes Reinecke wrote:
> > > On 1/21/21 9:14 PM, Keith Busch wrote:
> > > > On Thu, Jan 21, 2021 at 10:50:21AM +0100, Hannes Reinecke wrote:
> > > > > If the call to nvme_set_queue_count() fails with a status we should
> > > > > not ignore it but rather pass it on to the caller.
> > > > > It's then up to the transport to decide whether to ignore it
> > > > > (like PCI does) or to reset the connection (as would be appropriate
> > > > > for fabrics).
> > > > 
> > > > Instead of checking the error, wouldn't checking the number of created
> > > > queues be sufficient? What handling difference do you expect to occur
> > > > between getting a success with 0 queues, vs getting an error?
> > > > 
> > > The difference is that an error will (re-)start recovery, 0 queues won't.
> > > But the problem here is that nvme_set_queue_count() is being called during
> > > reconnection, ie during the recovery process itself.
> > > And this command is returned with a timeout, which in any other case is
> > > being treated as a fatal error. Plus we have been sending this command on
> > > the admin queue, so a timeout on the admin queue pretty much _is_  a fatal
> > > error. So we should be terminating the current recovery and reconnect. None
> > > of that will happen if we return '0' queues.
> > 
> > You should already be getting an error return status if a timeout occurs
> > for nvme_set_queue_count(), specifically -EINTR. Are you getting success
> > for some reason?
> > 
> -EINTR (which translates to 'nvme_req(req)->flags & NVME_REQ_CANCELLED')
> will only ever be returned on pci; fabrics doesn't set this flag, so we're
> never getting an -EINTR.

Sounds like that's the problem that needs to be fixed.


From Chaitanya.Kulkarni at wdc.com  Tue Jan 26 14:23:46 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Tue, 26 Jan 2021 19:23:46 +0000
Subject: RFC: nvme-cli: add "nvme monitor" subcommand
References: <79bd830da01238e1b36dd8e858e7cc29fcbf2876.camel@suse.com>
Message-ID: <BYAPR04MB4965D8F1CCBC27D60B242B7486BC9@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/26/21 3:48 AM, Martin Wilck wrote:
> Currently it handles only AENs and NVME-FC uevents, but it can be
> extended to other protocols in the future.
>
> Following the "publish early" principle, I'm posting this here now.
> My test results were positive so far.
>
> I've created a github PR with all the details here, please have a look:
>
> https://github.com/linux-nvme/nvme-cli/pull/877
>
> Issues with the CI came up after I submitted this, I'm working on that.

I had this in mind for a while especially with AENs for ZNS and other
device features.

Can you please create a patchset and post it on the mailing list ? also
please CC me.



From martin.wilck at suse.com  Tue Jan 26 15:24:03 2021
From: martin.wilck at suse.com (Martin Wilck)
Date: Tue, 26 Jan 2021 20:24:03 +0000
Subject: RFC: nvme-cli: add "nvme monitor" subcommand
In-Reply-To: <BYAPR04MB4965D8F1CCBC27D60B242B7486BC9@BYAPR04MB4965.namprd04.prod.outlook.com>
References: <79bd830da01238e1b36dd8e858e7cc29fcbf2876.camel@suse.com>
 <BYAPR04MB4965D8F1CCBC27D60B242B7486BC9@BYAPR04MB4965.namprd04.prod.outlook.com>
Message-ID: <efda478fa8c3eb79a3916a395c62be9671b6ff5d.camel@suse.com>

On Tue, 2021-01-26 at 19:23 +0000, Chaitanya Kulkarni wrote:
> On 1/26/21 3:48 AM, Martin Wilck wrote:
> > Currently it handles only AENs and NVME-FC uevents, but it can be
> > extended to other protocols in the future.
> > 
> > Following the "publish early" principle, I'm posting this here now.
> > My test results were positive so far.
> > 
> > I've created a github PR with all the details here, please have a
> > look:
> > 
> > https://github.com/linux-nvme/nvme-cli/pull/877
> > 
> > Issues with the CI came up after I submitted this, I'm working on
> > that.
> 
> I had this in mind for a while especially with AENs for ZNS and other
> device features.
> 
> Can you please create a patchset and post it on the mailing list ?
> also
> please CC me.

Will do. I won't CC everyone on from the cc list of this post though,
I don't want to spam people too much.

Thanks
Martin 


-- 
Dr. Martin Wilck <mwilck at suse.com>, Tel.?+49 (0)911 74053 2107
SUSE Software Solutions Germany GmbH
HRB 36809, AG N?rnberg GF: Felix Imend?rffer




From mwilck at suse.com  Tue Jan 26 15:32:51 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:32:51 +0100
Subject: [PATCH 02/35] monitor: create udev socket
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-3-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 monitor.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 47 insertions(+), 3 deletions(-)

diff --git a/monitor.c b/monitor.c
index dae4975..626827c 100644
--- a/monitor.c
+++ b/monitor.c
@@ -15,14 +15,58 @@
  * This file implements a simple monitor for NVMe-related uevents.
  */
 
+#include <stddef.h>
 #include <errno.h>
+#include <libudev.h>
 
 #include "nvme-status.h"
 #include "monitor.h"
 
-int aen_monitor(const char *desc, int argc, char **argv)
+static struct udev *udev;
+
+static void cleanup_monitor(struct udev_monitor **pmon)
 {
-	/* Handle as unimplemented for now */
-	return nvme_status_to_errno(-ENOTTY, true);
+	if (*pmon) {
+		udev_monitor_unref(*pmon);
+		*pmon = NULL;
+	}
 }
 
+static int create_udev_monitor(struct udev_monitor **pmon)
+{
+	struct udev_monitor *mon __attribute((cleanup(cleanup_monitor))) = NULL;
+	int ret;
+
+	if (!udev) {
+		udev = udev_new();
+		if (!udev)
+			return -ENOMEM;
+	}
+	mon = udev_monitor_new_from_netlink(udev, "kernel");
+	if (!mon)
+		return errno ? -errno : -ENOMEM;
+
+	/*
+	 * This fails in unpriviliged mode. Use the same value as udevd.
+	 * We may able to decrease this buffer size later.
+	 */
+	(void)udev_monitor_set_receive_buffer_size(mon, 128*1024*1024);
+	ret = udev_monitor_enable_receiving(mon);
+	if (ret < 0)
+		return ret;
+	*pmon = mon;
+	mon = NULL;
+	return 0;
+}
+
+int aen_monitor(const char *desc, int argc, char **argv)
+{
+	int ret;
+	struct udev_monitor *monitor;
+
+	ret = create_udev_monitor(&monitor);
+	if (ret == 0)
+		udev_monitor_unref(monitor);
+	udev = udev_unref(udev);
+	return nvme_status_to_errno(ret, true);
+}
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:32:52 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:32:52 +0100
Subject: [PATCH 03/35] monitor: initialize signal handling
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-4-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 monitor.c | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/monitor.c b/monitor.c
index 626827c..c7f4d85 100644
--- a/monitor.c
+++ b/monitor.c
@@ -16,8 +16,10 @@
  */
 
 #include <stddef.h>
+#include <stdio.h>
 #include <errno.h>
 #include <libudev.h>
+#include <signal.h>
 
 #include "nvme-status.h"
 #include "monitor.h"
@@ -59,14 +61,46 @@ static int create_udev_monitor(struct udev_monitor **pmon)
 	return 0;
 }
 
+static sig_atomic_t must_exit;
+
+static void monitor_int_handler(int sig)
+{
+	must_exit = 1;
+}
+
+static int monitor_init_signals(void)
+{
+	sigset_t mask;
+	struct sigaction sa = { .sa_handler = monitor_int_handler, };
+
+	/*
+	 * Block all signals. They will be unblocked when we wait
+	 * for events.
+	 */
+	sigfillset(&mask);
+	if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
+		return -errno;
+	if (sigaction(SIGTERM, &sa, NULL) == -1)
+		return -errno;
+	if (sigaction(SIGINT, &sa, NULL) == -1)
+		return -errno;
+	return 0;
+}
+
 int aen_monitor(const char *desc, int argc, char **argv)
 {
 	int ret;
 	struct udev_monitor *monitor;
 
+	ret = monitor_init_signals();
+	if (ret != 0) {
+		fprintf(stderr, "monitor: failed to initialize signals: %m\n");
+		goto out;
+	}
 	ret = create_udev_monitor(&monitor);
 	if (ret == 0)
 		udev_monitor_unref(monitor);
 	udev = udev_unref(udev);
+out:
 	return nvme_status_to_errno(ret, true);
 }
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:32:53 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:32:53 +0100
Subject: [PATCH 04/35] monitor: add main loop for uevent monitoring
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-5-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 monitor.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 77 insertions(+), 1 deletion(-)

diff --git a/monitor.c b/monitor.c
index c7f4d85..63e26bc 100644
--- a/monitor.c
+++ b/monitor.c
@@ -17,15 +17,25 @@
 
 #include <stddef.h>
 #include <stdio.h>
+#include <unistd.h>
 #include <errno.h>
 #include <libudev.h>
 #include <signal.h>
+#include <sys/epoll.h>
 
 #include "nvme-status.h"
 #include "monitor.h"
 
 static struct udev *udev;
 
+static void close_ptr(int *p)
+{
+	if (*p != -1) {
+		close(*p);
+		*p = -1;
+	}
+}
+
 static void cleanup_monitor(struct udev_monitor **pmon)
 {
 	if (*pmon) {
@@ -87,6 +97,70 @@ static int monitor_init_signals(void)
 	return 0;
 }
 
+static void monitor_handle_udevice(struct udev_device *ud)
+{
+	fprintf(stderr, "uevent: %s %s\n",
+		udev_device_get_action(ud),
+		udev_device_get_sysname(ud));
+}
+
+static void monitor_handle_uevents(struct udev_monitor *monitor)
+{
+	struct udev_device *ud;
+
+	for (ud = udev_monitor_receive_device(monitor);
+	     ud;
+	     ud = udev_monitor_receive_device(monitor)) {
+		monitor_handle_udevice(ud);
+		udev_device_unref(ud);
+	}
+}
+
+#define MAX_EVENTS 1
+static int monitor_main_loop(struct udev_monitor *monitor)
+{
+	int ep_fd __attribute__((cleanup(close_ptr))) = -1;
+	int ret;
+	struct epoll_event ep_ev = { .events = EPOLLIN, };
+	struct epoll_event events[MAX_EVENTS];
+	sigset_t ep_mask;
+
+	ep_fd = epoll_create1(0);
+	if (ep_fd == -1)
+		return -errno;
+	ep_ev.data.ptr = monitor;
+	ret = epoll_ctl(ep_fd, EPOLL_CTL_ADD,
+			udev_monitor_get_fd(monitor), &ep_ev);
+	if (ret == -1)
+		return -errno;
+
+	sigfillset(&ep_mask);
+	sigdelset(&ep_mask, SIGTERM);
+	sigdelset(&ep_mask, SIGINT);
+	while (1) {
+		int rc, i;
+
+		rc = epoll_pwait(ep_fd, events, MAX_EVENTS, -1, &ep_mask);
+		if (rc == -1 && errno == EINTR) {
+			fprintf(stderr, "monitor: exit signal received\n");
+			return 0;
+		} else if (rc == -1) {
+			fprintf(stderr, "monitor: epoll_wait: %m\n");
+			return -errno;
+		} else if (rc == 0 || rc > MAX_EVENTS) {
+			fprintf(stderr, "monitor: epoll_wait: unexpected rc=%d\n", rc);
+			continue;
+		}
+		for (i = 0; i < MAX_EVENTS; i++) {
+			if (events[i].data.ptr == monitor)
+				(void)monitor_handle_uevents(monitor);
+			else
+				fprintf(stderr, "monitor: unexpected event\n");
+		}
+	}
+	return ret;
+}
+
 int aen_monitor(const char *desc, int argc, char **argv)
 {
 	int ret;
@@ -98,8 +172,10 @@ int aen_monitor(const char *desc, int argc, char **argv)
 		goto out;
 	}
 	ret = create_udev_monitor(&monitor);
-	if (ret == 0)
+	if (ret == 0) {
+		ret = monitor_main_loop(monitor);
 		udev_monitor_unref(monitor);
+	}
 	udev = udev_unref(udev);
 out:
 	return nvme_status_to_errno(ret, true);
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:32:50 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:32:50 +0100
Subject: [PATCH 01/35] nvme-monitor: add new stub
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-2-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

This stub will become the nvme AEN monitor in follow-up commits.
monitor functionality depends on libudev.

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 Makefile       | 10 ++++++++++
 monitor.c      | 28 ++++++++++++++++++++++++++++
 monitor.h      |  6 ++++++
 nvme-builtin.h |  1 +
 nvme.c         | 13 +++++++++++++
 5 files changed, 58 insertions(+)
 create mode 100644 monitor.c
 create mode 100644 monitor.h

diff --git a/Makefile b/Makefile
index 3ea17b5..21c9a23 100644
--- a/Makefile
+++ b/Makefile
@@ -4,6 +4,7 @@ override CPPFLAGS += -D_GNU_SOURCE -D__CHECK_ENDIAN__
 LIBUUID = $(shell $(LD) -o /dev/null -luuid >/dev/null 2>&1; echo $$?)
 LIBHUGETLBFS = $(shell $(LD) -o /dev/null -lhugetlbfs >/dev/null 2>&1; echo $$?)
 HAVE_SYSTEMD = $(shell pkg-config --exists libsystemd  --atleast-version=242; echo $$?)
+HAVE_LIBUDEV = $(shell pkg-config --exists libudev; echo $$?)
 NVME = nvme
 INSTALL ?= install
 DESTDIR =
@@ -32,6 +33,11 @@ endif
 
 INC=-Iutil
 
+ifeq ($(HAVE_LIBUDEV),0)
+	override LDFLAGS += -ludev
+	override CFLAGS += -DHAVE_LIBUDEV
+endif
+
 ifeq ($(HAVE_SYSTEMD),0)
 	override LDFLAGS += -lsystemd
 	override CFLAGS += -DHAVE_SYSTEMD
@@ -62,6 +68,10 @@ OBJS := nvme-print.o nvme-ioctl.o nvme-rpmb.o \
 	nvme-lightnvm.o fabrics.o nvme-models.o plugin.o \
 	nvme-status.o nvme-filters.o nvme-topology.o
 
+ifeq ($(HAVE_LIBUDEV),0)
+	OBJS += monitor.o
+endif
+
 UTIL_OBJS := util/argconfig.o util/suffix.o util/json.o util/parser.o
 
 PLUGIN_OBJS :=					\
diff --git a/monitor.c b/monitor.c
new file mode 100644
index 0000000..dae4975
--- /dev/null
+++ b/monitor.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2021 SUSE LLC
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This file implements a simple monitor for NVMe-related uevents.
+ */
+
+#include <errno.h>
+
+#include "nvme-status.h"
+#include "monitor.h"
+
+int aen_monitor(const char *desc, int argc, char **argv)
+{
+	/* Handle as unimplemented for now */
+	return nvme_status_to_errno(-ENOTTY, true);
+}
+
diff --git a/monitor.h b/monitor.h
new file mode 100644
index 0000000..e79d3a6
--- /dev/null
+++ b/monitor.h
@@ -0,0 +1,6 @@
+#ifndef _MONITOR_H
+#define _MONITOR_H
+
+extern int aen_monitor(const char *desc, int argc, char **argv);
+
+#endif
diff --git a/nvme-builtin.h b/nvme-builtin.h
index 59896dc..74f9a3e 100644
--- a/nvme-builtin.h
+++ b/nvme-builtin.h
@@ -80,6 +80,7 @@ COMMAND_LIST(
 	ENTRY("dir-send", "Submit a Directive Send command, return results", dir_send)
 	ENTRY("virt-mgmt", "Manage Flexible Resources between Primary and Secondary Controller ", virtual_mgmt)
 	ENTRY("rpmb", "Replay Protection Memory Block commands", rpmb_cmd)
+	ENTRY("monitor", "Monitor NVMeoF AEN events", monitor_cmd)
 );
 
 #endif
diff --git a/nvme.c b/nvme.c
index d1ef6e9..d2004a2 100644
--- a/nvme.c
+++ b/nvme.c
@@ -57,6 +57,7 @@
 
 #include "argconfig.h"
 #include "fabrics.h"
+#include "monitor.h"
 
 #define CREATE_CMD
 #include "nvme-builtin.h"
@@ -5320,6 +5321,18 @@ static int disconnect_all_cmd(int argc, char **argv, struct command *command, st
 	return fabrics_disconnect_all(desc, argc, argv);
 }
 
+static int monitor_cmd(int argc, char **argv, struct command *command, struct plugin *plugin)
+{
+#ifdef HAVE_LIBUDEV
+	const char *desc = "Monitor NVMeoF AEN events";
+
+	return aen_monitor(desc, argc, argv);
+#else
+	fprintf(stderr, "nvme-cli built without libudev doesn't support the \"monitor\" subcommand\n");
+	return EOPNOTSUPP;
+#endif
+}
+
 void register_extension(struct plugin *plugin)
 {
 	plugin->parent = &nvme;
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:32:49 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:32:49 +0100
Subject: [PATCH 00/35] RFC: add "nvme monitor" subcommand
Message-ID: <20210126203324.23610-1-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

(Cover letter copied from https://github.com/linux-nvme/nvme-cli/pull/877)

This patch set adds a new subcommand **nvme monitor**. In this mode,
**nvme-cli** runs continuously, monitors events (currently, uevents) relevant
for discovery, and optionally autoconnects to newly discovered subsystems.

The monitor mode is suitable to be run in a systemd service. An appropriate
unit file is provided. As such, **nvme monitor** can be used as an alternative
to the current auto-connection mechanism based on udev rules and systemd
template units. If `--autoconnect` is active, **nvme monitor** masks the
respective udev rules in order to prevent simultaneous connection attempts
from udev and itself.

This method for discovery and autodetection has some advantages over the
current udev-rule based approach:

 * By using the `--persistent` option, users can easily control whether
   persistent discovery controllers for discovered transport addresses should
   be created and monitored for AEN events. **nvme monitor** watches known
   transport addresses, creates discovery controllers as required, and re-uses
   existing ones if possible. It keeps track of persistent discovery
   controllers it created, and tears them down on exit. When run in
   `--persistent --autoconnect` mode *in the initial ramfs*, it will keep
   discovery controllers alive, so that a new instance started after switching
   root can simply re-use them.
 * In certain situations, the systemd-based approach may miss events due to
   race conditions. This can happen e.g. if an FC remote port is detected, but
   shortly after it's detection an FC relogin procedure is necessary e.g. due to
   an RSCN. In this case, an `fc_udev_device` uevent will be received on the
   first detection and handled by an `nvme connect-all` command run from
   `nvmf-connect at .service`. The connection attempt to the rport in question will
   fail with "no such device" because of the simultaneous FC
   relogin. `nvmf-connect at .service` may not terminate immediately, because it
   attempts to establish other connections listed in the Discovery Log page it
   retrieved. When the FC relogin eventually finishes, a new uevent will be
   received, and `nvmf-connect@` will be started again, but *this has no effect*
   if the previous `nvmf-connect@` service hasn't finished yet. This is the
   general semantics of systemd services, no easy workaround exists.  **nvme
   monitor** doesn't suffer from this problem. If it sees an uevent for a
   transport address for which a discovery is already running, it will queue the
   handling of this event up and restart the discovery after it's finished.
 * Resource consumption for handling uevents is lower. Instead of running an
   udev worker, executing the rules, executing `systemctl start` from the
   worker, starting a systemd service, and starting a separate **nvme-cli**
   instance, only a single `fork()` operation is necessary. Of course, on the
   back side, the monitor itself consumes resources while it's running and
   waiting for events. On my system with 8 persistent discovery controllers,
   its RSS is ~3MB. CPU consumption is zero as long as no events occur.
 * **nvme monitor** could be easily extended to handle events for non-FC
   transports.

I've tested `fc_udev_device` handling for NVMeoFC with an Ontap target, and
AEN handling for RDMA using a Linux **nvmet** target.

### Implementation notes

I've tried to change the exisiting **nvme-cli** code as little as possible
while reusing the code from `fabrics.c`. The majority of changes in the
existing code exports formerly static functions and variables, so that they
are usable from the monitor code.

The main process just waits for events using `epoll()`. When an event is
received that necessitates a new discovery, a child is forked. This makes it
possible to fill in the configuration parameters for `do_discover()` without
interfering with the main process or other discovery tasks running in
parallel. The program tracks *transport addresses* (called "connections" in
the code) rather than NVMe controllers. In `--persistent` mode, it tries to
maintain exactly one persistent discovery connection per transport address.

Using `epoll()` may look over-engineered at this stage. I hope the better
flexibility over `poll()` (in particular, the ability to add new event sources
while waiting) will simplify future extensions and improvements.

### Todo

 * Referrals are not handled perfectly yet. They will be handled by
   `do_discover()` just as it would when called from **nvme connect-all**, but
   it would be better to pass referrals back to the main process to make it
   aware of the additional discovery controller rather than using
   recursion. The main process would e.g. know if a discovery is already
   running for the transport address in the referrral.
 *  When "add" uevents for nvme controller devices are received, the
    controller is consistently not in `live` state yet, and attempting to read
    the `subsysnqn` sysfs attribute returns `(efault)`. While this should
    arguably be fixed in the kernel, it could be worked around in user space
    by using timers or polling the `state` sysfs attribute for changes.
 * Parse and handle `discovery.conf` on startup.
 * Implement support for RDMA and TCP protocols.


Martin Wilck (35):
  nvme-monitor: add new stub
  monitor: create udev socket
  monitor: initialize signal handling
  monitor: add main loop for uevent monitoring
  monitor: add uevent filters
  monitor: Create a log() macro.
  fabrics: use log() macro
  monitor: add command line options to control logging
  nvme_get_ctrl_attr(): constify "path" argument
  fabrics: export do_discover(), build_options() and config
  monitor: add option -A / --autoconnect
  monitor: add helpers for __attribute__((cleanup))
  monitor: disable nvmf-autoconnect udev rules in autoconnect mode
  monitor: implement handling of fc_udev_device
  monitor: implement handling of nvme AEN events
  monitor: reset children's signal disposition
  monitor: handle SIGCHLD for terminated child processes
  monitor: add "--persistent/-p" flag
  fabrics: use "const char *" in struct config
  fabrics: export arg_str(), parse_conn_arg(), and remove_ctrl()
  nvme-cli: add "list.h"
  conn-db: add simple connection registry
  monitor: handle restart of pending discoveries
  monitor: monitor_discovery(): try to reuse existing controllers
  monitor: read existing connections on startup
  monitor: implement starting discovery controllers on startup
  monitor: implement cleanup of created discovery controllers
  monitor: basic handling of add/remove uevents for nvme controllers
  monitor: kill running discovery tasks on exit
  monitor: add connection property options from connect-all
  completions: add completions for nvme monitor
  nvmf-autoconnect: add unit file for nvme-monitor.service
  nvme-connect-all(1): fix documentation for --quiet/-S
  nvme-monitor(1): add man page for nvme-monitor
  monitor: add option --keep/-K

 Documentation/cmds-main.txt                   |    4 +
 Documentation/nvme-connect-all.1              |    8 +-
 Documentation/nvme-connect-all.html           |   10 +-
 Documentation/nvme-connect-all.txt            |    4 +-
 Documentation/nvme-monitor.1                  |  218 ++++
 Documentation/nvme-monitor.html               | 1067 +++++++++++++++++
 Documentation/nvme-monitor.txt                |  170 +++
 Makefile                                      |   10 +
 common.h                                      |   12 +
 completions/bash-nvme-completion.sh           |    6 +-
 conn-db.c                                     |  341 ++++++
 conn-db.h                                     |  141 +++
 fabrics.c                                     |  145 +--
 fabrics.h                                     |   39 +
 list.h                                        |  365 ++++++
 log.h                                         |   44 +
 monitor.c                                     |  764 ++++++++++++
 monitor.h                                     |    6 +
 nvme-builtin.h                                |    1 +
 nvme-topology.c                               |    2 +-
 nvme.c                                        |   13 +
 nvme.h                                        |    2 +-
 nvmf-autoconnect/systemd/nvme-monitor.service |   17 +
 23 files changed, 3296 insertions(+), 93 deletions(-)
 create mode 100644 Documentation/nvme-monitor.1
 create mode 100644 Documentation/nvme-monitor.html
 create mode 100644 Documentation/nvme-monitor.txt
 create mode 100644 conn-db.c
 create mode 100644 conn-db.h
 create mode 100644 list.h
 create mode 100644 log.h
 create mode 100644 monitor.c
 create mode 100644 monitor.h
 create mode 100644 nvmf-autoconnect/systemd/nvme-monitor.service

-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:32:54 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:32:54 +0100
Subject: [PATCH 05/35] monitor: add uevent filters
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-6-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 monitor.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/monitor.c b/monitor.c
index 63e26bc..a6c8905 100644
--- a/monitor.c
+++ b/monitor.c
@@ -58,6 +58,10 @@ static int create_udev_monitor(struct udev_monitor **pmon)
 	if (!mon)
 		return errno ? -errno : -ENOMEM;
 
+	/* Add match for NVMe controller devices */
+	ret = udev_monitor_filter_add_match_subsystem_devtype(mon, "nvme", NULL);
+	/* Add match for fc_udev_device */
+	ret = udev_monitor_filter_add_match_subsystem_devtype(mon, "fc", NULL);
 	/*
 	 * This fails in unpriviliged mode. Use the same value as udevd.
 	 * We may able to decrease this buffer size later.
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:32:55 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:32:55 +0100
Subject: [PATCH 06/35] monitor: Create a log() macro.
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-7-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

As this is a long running program, we need to make the log output
configurable. First step: replace fprintf() by log(). The log level
and printing of time stamps can be configured at run time using
global variables. These will live in fabrics.c.

Allow toggling function name printing at build time.
Printing the function name is useful for development, but perhaps
not desired for production.
Put '#define LOG_FUNCNAME' before '#include "log.h"' to switch it on.

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 log.h | 44 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)
 create mode 100644 log.h

diff --git a/log.h b/log.h
new file mode 100644
index 0000000..2017731
--- /dev/null
+++ b/log.h
@@ -0,0 +1,44 @@
+#ifndef _LOG_H
+#define _LOG_H
+
+#ifndef MAX_LOGLEVEL
+#  define MAX_LOGLEVEL LOG_DEBUG
+#endif
+#ifndef DEFAULT_LOGLEVEL
+#  define DEFAULT_LOGLEVEL LOG_NOTICE
+#endif
+
+#ifdef LOG_FUNCNAME
+#define _func_fmt "%s: "
+#define _func_arg __func__
+#else
+#define _func_fmt "%s"
+#define _func_arg ""
+#endif
+
+extern int log_level;
+extern bool log_timestamp;
+#define _TIME_FMT "[%ld.%06ld] "
+#define log(lvl, format, ...) \
+	do {								\
+		int __lvl = (lvl);					\
+									\
+		if (__lvl <= MAX_LOGLEVEL && __lvl <= log_level) {	\
+			if (log_timestamp) {				\
+				struct timespec __ts;			\
+									\
+				clock_gettime(CLOCK_MONOTONIC, &__ts);	\
+				fprintf(stderr,				\
+					_TIME_FMT _func_fmt format,	\
+					__ts.tv_sec, __ts.tv_nsec / 1000,\
+					_func_arg,			\
+					##__VA_ARGS__);			\
+			} else {					\
+				fprintf(stderr, _func_fmt format,	\
+					_func_arg,			\
+					##__VA_ARGS__);			\
+			};						\
+		}							\
+	} while (0)
+
+#endif /* _LOG_H */
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:32:57 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:32:57 +0100
Subject: [PATCH 08/35] monitor: add command line options to control logging
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-9-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

Standard syslog loglevels are used.
Options:

 -S/--silent   to suppress LOG_NOTICE
 -v/--verbose  to enable LOG_INFO (overrides -S)
 -D/--debug    to enable LOG_DEBUG (overrides -S, -v)
 -C/--clockstamps to enable time stamps on log messages.

I tried to use short options that don't conflict with options
from nvme connect-all, because many of those options might be
useful for the monitor, too.

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 monitor.c | 47 +++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 41 insertions(+), 6 deletions(-)

diff --git a/monitor.c b/monitor.c
index a6c8905..a7afa1c 100644
--- a/monitor.c
+++ b/monitor.c
@@ -21,10 +21,15 @@
 #include <errno.h>
 #include <libudev.h>
 #include <signal.h>
+#include <time.h>
+#include <syslog.h>
 #include <sys/epoll.h>
 
 #include "nvme-status.h"
+#include "util/argconfig.h"
 #include "monitor.h"
+#define LOG_FUNCNAME 1
+#include "log.h"
 
 static struct udev *udev;
 
@@ -103,7 +108,7 @@ static int monitor_init_signals(void)
 
 static void monitor_handle_udevice(struct udev_device *ud)
 {
-	fprintf(stderr, "uevent: %s %s\n",
+	log(LOG_INFO, "uevent: %s %s\n",
 		udev_device_get_action(ud),
 		udev_device_get_sysname(ud));
 }
@@ -146,33 +151,63 @@ static int monitor_main_loop(struct udev_monitor *monitor)
 
 		rc = epoll_pwait(ep_fd, events, MAX_EVENTS, -1, &ep_mask);
 		if (rc == -1 && errno == EINTR) {
-			fprintf(stderr, "monitor: exit signal received\n");
+			log(LOG_NOTICE, "monitor: exit signal received\n");
 			return 0;
 		} else if (rc == -1) {
-			fprintf(stderr, "monitor: epoll_wait: %m\n");
+			log(LOG_ERR, "monitor: epoll_wait: %m\n");
 			return -errno;
 		} else if (rc == 0 || rc > MAX_EVENTS) {
-			fprintf(stderr, "monitor: epoll_wait: unexpected rc=%d\n", rc);
+			log(LOG_ERR, "monitor: epoll_wait: unexpected rc=%d\n", rc);
 			continue;
 		}
 		for (i = 0; i < MAX_EVENTS; i++) {
 			if (events[i].data.ptr == monitor)
 				(void)monitor_handle_uevents(monitor);
 			else
-				fprintf(stderr, "monitor: unexpected event\n");
+				log(LOG_ERR, "monitor: unexpected event\n");
 		}
 	}
 	return ret;
 }
 
+static int monitor_parse_opts(const char *desc, int argc, char **argv)
+{
+	bool quiet = false;
+	bool verbose = false;
+	bool debug = false;
+	int ret;
+	OPT_ARGS(opts) = {
+		OPT_FLAG("silent",         'S', &quiet,               "log level: silent"),
+		OPT_FLAG("verbose",        'v', &verbose,             "log level: verbose"),
+		OPT_FLAG("debug",          'D', &debug,               "log level: debug"),
+		OPT_FLAG("clockstamps",    'C', &log_timestamp,       "print log timestamps"),
+		OPT_END()
+	};
+
+	ret = argconfig_parse(argc, argv, desc, opts);
+	if (ret)
+		return ret;
+	if (quiet)
+		log_level = LOG_WARNING;
+	if (verbose)
+		log_level = LOG_INFO;
+	if (debug)
+		log_level = LOG_DEBUG;
+
+	return ret;
+}
+
 int aen_monitor(const char *desc, int argc, char **argv)
 {
 	int ret;
 	struct udev_monitor *monitor;
 
+	ret = monitor_parse_opts(desc, argc, argv);
+	if (ret)
+		goto out;
 	ret = monitor_init_signals();
 	if (ret != 0) {
-		fprintf(stderr, "monitor: failed to initialize signals: %m\n");
+		log(LOG_ERR, "monitor: failed to initialize signals: %m\n");
 		goto out;
 	}
 	ret = create_udev_monitor(&monitor);
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:32:58 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:32:58 +0100
Subject: [PATCH 09/35] nvme_get_ctrl_attr(): constify "path" argument
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-10-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 nvme-topology.c | 2 +-
 nvme.h          | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/nvme-topology.c b/nvme-topology.c
index 71371c5..f62446b 100644
--- a/nvme-topology.c
+++ b/nvme-topology.c
@@ -45,7 +45,7 @@ close_fd:
 	return subsysnqn;
 }
 
-char *nvme_get_ctrl_attr(char *path, const char *attr)
+char *nvme_get_ctrl_attr(const char *path, const char *attr)
 {
 	char *attrpath, *value;
 	ssize_t ret;
diff --git a/nvme.h b/nvme.h
index 3fb1060..382e625 100644
--- a/nvme.h
+++ b/nvme.h
@@ -109,7 +109,7 @@ int scan_subsystems(struct nvme_topology *t, const char *subsysnqn,
 		    __u32 ns_instance, char *dev_dir);
 void free_topology(struct nvme_topology *t);
 char *get_nvme_subsnqn(char *path);
-char *nvme_get_ctrl_attr(char *path, const char *attr);
+char *nvme_get_ctrl_attr(const char *path, const char *attr);
 
 void *nvme_alloc(size_t len, bool *huge);
 void nvme_free(void *p, bool huge);
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:32:59 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:32:59 +0100
Subject: [PATCH 10/35] fabrics: export do_discover(),
 build_options() and config
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-11-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

These functions will be called by the monitor code.
Also export BUF_SIZE as the size of argstr.

Being able to access struct config and the "cfg" variable
from fabrics.c is essential for the monitor to leverage the existing,
well tested code as much as possible.

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 fabrics.c | 33 ++++-----------------------------
 fabrics.h | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 38 insertions(+), 29 deletions(-)

diff --git a/fabrics.c b/fabrics.c
index 555b6b4..c1a4bb5 100644
--- a/fabrics.c
+++ b/fabrics.c
@@ -69,31 +69,7 @@ const char *conarg_traddr = "traddr";
 const char *conarg_trsvcid = "trsvcid";
 const char *conarg_host_traddr = "host_traddr";
 
-static struct config {
-	char *nqn;
-	char *transport;
-	char *traddr;
-	char *trsvcid;
-	char *host_traddr;
-	char *hostnqn;
-	char *hostid;
-	int  nr_io_queues;
-	int  nr_write_queues;
-	int  nr_poll_queues;
-	int  queue_size;
-	int  keep_alive_tmo;
-	int  reconnect_delay;
-	int  ctrl_loss_tmo;
-	int  tos;
-	char *raw;
-	char *device;
-	int  duplicate_connect;
-	int  disable_sqflow;
-	int  hdr_digest;
-	int  data_digest;
-	bool persistent;
-	bool matching_only;
-} cfg = { .ctrl_loss_tmo = NVMF_DEF_CTRL_LOSS_TMO };
+struct config cfg = { .ctrl_loss_tmo = NVMF_DEF_CTRL_LOSS_TMO };
 
 struct connect_args {
 	char *subsysnqn;
@@ -107,7 +83,6 @@ struct connect_args {
 
 struct connect_args *tracked_ctrls;
 
-#define BUF_SIZE		4096
 #define PATH_NVME_FABRICS	"/dev/nvme-fabrics"
 #define PATH_NVMF_DISC		"/etc/nvme/discovery.conf"
 #define PATH_NVMF_HOSTNQN	"/etc/nvme/hostnqn"
@@ -226,7 +201,7 @@ static const char *cms_str(__u8 cm)
 	return arg_str(cms, ARRAY_SIZE(cms), cm);
 }
 
-static int do_discover(char *argstr, bool connect);
+int do_discover(char *argstr, bool connect);
 
 /*
  * parse strings with connect arguments to find a particular field.
@@ -855,7 +830,7 @@ add_argument(char **argstr, int *max_len, char *arg_str, char *arg)
 	return 0;
 }
 
-static int build_options(char *argstr, int max_len, bool discover)
+int build_options(char *argstr, int max_len, bool discover)
 {
 	int len;
 
@@ -1264,7 +1239,7 @@ static void nvmf_get_host_identifiers(int ctrl_instance)
 	cfg.hostid = nvme_get_ctrl_attr(path, "hostid");
 }
 
-static int do_discover(char *argstr, bool connect)
+int do_discover(char *argstr, bool connect)
 {
 	struct nvmf_disc_rsp_page_hdr *log = NULL;
 	char *dev_name;
diff --git a/fabrics.h b/fabrics.h
index f5b8eaf..ce965a3 100644
--- a/fabrics.h
+++ b/fabrics.h
@@ -10,4 +10,38 @@ extern int fabrics_connect(const char *desc, int argc, char **argv);
 extern int fabrics_disconnect(const char *desc, int argc, char **argv);
 extern int fabrics_disconnect_all(const char *desc, int argc, char **argv);
 
+/* Symbols used by monitor.c */
+
+struct config {
+	char *nqn;
+	char *transport;
+	char *traddr;
+	char *trsvcid;
+	char *host_traddr;
+	char *hostnqn;
+	char *hostid;
+	int  nr_io_queues;
+	int  nr_write_queues;
+	int  nr_poll_queues;
+	int  queue_size;
+	int  keep_alive_tmo;
+	int  reconnect_delay;
+	int  ctrl_loss_tmo;
+	int  tos;
+	char *raw;
+	char *device;
+	int  duplicate_connect;
+	int  disable_sqflow;
+	int  hdr_digest;
+	int  data_digest;
+	bool persistent;
+	bool matching_only;
+};
+extern struct config cfg;
+
+#define BUF_SIZE 4096
+
+int build_options(char *argstr, int max_len, bool discover);
+int do_discover(char *argstr, bool connect);
+
 #endif
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:32:56 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:32:56 +0100
Subject: [PATCH 07/35] fabrics: use log() macro
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-8-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

Fabrics functionality will be used by the monitor code, we
need consistent logging. This patch causes no functional change
for the fabrics module.

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 fabrics.c | 83 ++++++++++++++++++++++++++++++-------------------------
 1 file changed, 45 insertions(+), 38 deletions(-)

diff --git a/fabrics.c b/fabrics.c
index 17711cf..555b6b4 100644
--- a/fabrics.c
+++ b/fabrics.c
@@ -32,6 +32,8 @@
 #include <libgen.h>
 #include <sys/stat.h>
 #include <stddef.h>
+#include <syslog.h>
+#include <time.h>
 
 #include <sys/types.h>
 #include <arpa/inet.h>
@@ -46,6 +48,10 @@
 #include "util/argconfig.h"
 
 #include "common.h"
+#include "log.h"
+
+int log_level = LOG_NOTICE;
+bool log_timestamp;
 
 #ifdef HAVE_SYSTEMD
 #include <systemd/sd-id128.h>
@@ -86,7 +92,6 @@ static struct config {
 	int  hdr_digest;
 	int  data_digest;
 	bool persistent;
-	bool quiet;
 	bool matching_only;
 } cfg = { .ctrl_loss_tmo = NVMF_DEF_CTRL_LOSS_TMO };
 
@@ -345,7 +350,7 @@ static char *find_ctrl_with_connectargs(struct connect_args *args)
 
 	n = scandir(SYS_NVME, &devices, scan_ctrls_filter, alphasort);
 	if (n < 0) {
-		fprintf(stderr, "no NVMe controller(s) detected.\n");
+		log(LOG_ERR, "no NVMe controller(s) detected.\n");
 		return NULL;
 	}
 
@@ -353,7 +358,7 @@ static char *find_ctrl_with_connectargs(struct connect_args *args)
 		if (ctrl_matches_connectargs(devices[i]->d_name, args)) {
 			devname = strdup(devices[i]->d_name);
 			if (devname == NULL)
-				fprintf(stderr, "no memory for ctrl name %s\n",
+				log(LOG_ERR, "no memory for ctrl name %s\n",
 						devices[i]->d_name);
 			goto cleanup_devices;
 		}
@@ -415,7 +420,7 @@ static int add_ctrl(const char *argstr)
 
 	fd = open(PATH_NVME_FABRICS, O_RDWR);
 	if (fd < 0) {
-		fprintf(stderr, "Failed to open %s: %s\n",
+		log(LOG_ERR, "Failed to open %s: %s\n",
 			 PATH_NVME_FABRICS, strerror(errno));
 		ret = -errno;
 		goto out;
@@ -423,8 +428,8 @@ static int add_ctrl(const char *argstr)
 
 	ret = write(fd, argstr, len);
 	if (ret != len) {
-		if (errno != EALREADY || !cfg.quiet)
-			fprintf(stderr, "Failed to write to %s: %s\n",
+		if (errno != EALREADY)
+			log(LOG_NOTICE, "Failed to write to %s: %s\n",
 				 PATH_NVME_FABRICS, strerror(errno));
 		ret = -errno;
 		goto out_close;
@@ -432,7 +437,7 @@ static int add_ctrl(const char *argstr)
 
 	len = read(fd, buf, BUF_SIZE);
 	if (len < 0) {
-		fprintf(stderr, "Failed to read from %s: %s\n",
+		log(LOG_ERR, "Failed to read from %s: %s\n",
 			 PATH_NVME_FABRICS, strerror(errno));
 		ret = -errno;
 		goto out_close;
@@ -459,7 +464,7 @@ static int add_ctrl(const char *argstr)
 	}
 
 out_fail:
-	fprintf(stderr, "Failed to parse ctrl info for \"%s\"\n", argstr);
+	log(LOG_ERR, "Failed to parse ctrl info for \"%s\"\n", argstr);
 	ret = -EINVAL;
 out_close:
 	close(fd);
@@ -474,7 +479,7 @@ static int remove_ctrl_by_path(char *sysfs_path)
 	fd = open(sysfs_path, O_WRONLY);
 	if (fd < 0) {
 		ret = -errno;
-		fprintf(stderr, "Failed to open %s: %s\n", sysfs_path,
+		log(LOG_ERR, "Failed to open %s: %s\n", sysfs_path,
 				strerror(errno));
 		goto out;
 	}
@@ -528,7 +533,7 @@ static int nvmf_get_log_page_discovery(const char *dev_path,
 	fd = open(dev_path, O_RDWR);
 	if (fd < 0) {
 		error = -errno;
-		fprintf(stderr, "Failed to open %s: %s\n",
+		log(LOG_ERR, "Failed to open %s: %s\n",
 				dev_path, strerror(errno));
 		goto out;
 	}
@@ -699,7 +704,7 @@ static void save_discovery_log(struct nvmf_disc_rsp_page_hdr *log, int numrec)
 
 	fd = open(cfg.raw, O_CREAT|O_RDWR|O_TRUNC, S_IRUSR|S_IWUSR);
 	if (fd < 0) {
-		fprintf(stderr, "failed to open %s: %s\n",
+		log(LOG_ERR, "failed to open %s: %s\n",
 			cfg.raw, strerror(errno));
 		return;
 	}
@@ -708,7 +713,7 @@ static void save_discovery_log(struct nvmf_disc_rsp_page_hdr *log, int numrec)
 			numrec * sizeof(struct nvmf_disc_rsp_page_entry);
 	ret = write(fd, log, len);
 	if (ret < 0)
-		fprintf(stderr, "failed to write to %s: %s\n",
+		log(LOG_ERR, "failed to write to %s: %s\n",
 			cfg.raw, strerror(errno));
 	else
 		printf("Discovery log is saved to %s\n", cfg.raw);
@@ -855,13 +860,13 @@ static int build_options(char *argstr, int max_len, bool discover)
 	int len;
 
 	if (!cfg.transport) {
-		fprintf(stderr, "need a transport (-t) argument\n");
+		log(LOG_ERR, "need a transport (-t) argument\n");
 		return -EINVAL;
 	}
 
 	if (strncmp(cfg.transport, "loop", 4)) {
 		if (!cfg.traddr) {
-			fprintf(stderr, "need a address (-a) argument\n");
+			log(LOG_ERR, "need a address (-a) argument\n");
 			return -EINVAL;
 		}
 	}
@@ -945,7 +950,7 @@ static int hostname2traddr(struct config *cfg)
 
 	ret = getaddrinfo(cfg->traddr, NULL, &hints, &host_info);
 	if (ret) {
-		fprintf(stderr, "failed to resolve host %s info\n", cfg->traddr);
+		log(LOG_ERR, "failed to resolve host %s info\n", cfg->traddr);
 		return ret;
 	}
 
@@ -961,14 +966,14 @@ static int hostname2traddr(struct config *cfg)
 			addrstr, NVMF_TRADDR_SIZE);
 		break;
 	default:
-		fprintf(stderr, "unrecognized address family (%d) %s\n",
+		log(LOG_ERR, "unrecognized address family (%d) %s\n",
 			host_info->ai_family, cfg->traddr);
 		ret = -EINVAL;
 		goto free_addrinfo;
 	}
 
 	if (!p) {
-		fprintf(stderr, "failed to get traddr for %s\n", cfg->traddr);
+		log(LOG_ERR, "failed to get traddr for %s\n", cfg->traddr);
 		ret = -errno;
 		goto free_addrinfo;
 	}
@@ -996,7 +1001,7 @@ retry:
 	case NVME_NQN_NVME:
 		break;
 	default:
-		fprintf(stderr, "skipping unsupported subtype %d\n",
+		log(LOG_ERR, "skipping unsupported subtype %d\n",
 			 e->subtype);
 		return -EINVAL;
 	}
@@ -1085,7 +1090,7 @@ retry:
 
 	transport = trtype_str(e->trtype);
 	if (!strcmp(transport, "unrecognized")) {
-		fprintf(stderr, "skipping unsupported transport %d\n",
+		log(LOG_ERR, "skipping unsupported transport %d\n",
 				 e->trtype);
 		return -EINVAL;
 	}
@@ -1131,7 +1136,7 @@ retry:
 			p += len;
 			break;
 		default:
-			fprintf(stderr, "skipping unsupported adrfam\n");
+			log(LOG_ERR, "skipping unsupported adrfam\n");
 			return -EINVAL;
 		}
 		break;
@@ -1146,7 +1151,7 @@ retry:
 			p += len;
 			break;
 		default:
-			fprintf(stderr, "skipping unsupported adrfam\n");
+			log(LOG_ERR, "skipping unsupported adrfam\n");
 			return -EINVAL;
 		}
 		break;
@@ -1231,9 +1236,7 @@ static int connect_ctrls(struct nvmf_disc_rsp_page_hdr *log, int numrec)
 		if (instance == -EALREADY) {
 			const char *traddr = log->entries[i].traddr;
 
-			if (!cfg.quiet)
-				fprintf(stderr,
-					"traddr=%.*s is already connected\n",
+			log(LOG_NOTICE, "traddr=%.*s is already connected\n",
 					space_strip_len(NVMF_TRADDR_SIZE,
 							traddr),
 					traddr);
@@ -1321,12 +1324,12 @@ static int do_discover(char *argstr, bool connect)
 			print_discovery_log(log, numrec);
 		break;
 	case DISC_GET_NUMRECS:
-		fprintf(stderr,
+		log(LOG_ERR,
 			"Get number of discovery log entries failed.\n");
 		ret = status;
 		break;
 	case DISC_GET_LOG:
-		fprintf(stderr, "Get discovery log entries failed.\n");
+		log(LOG_ERR, "Get discovery log entries failed.\n");
 		ret = status;
 		break;
 	case DISC_NO_LOG:
@@ -1338,12 +1341,12 @@ static int do_discover(char *argstr, bool connect)
 		ret = -EAGAIN;
 		break;
 	case DISC_NOT_EQUAL:
-		fprintf(stderr,
+		log(LOG_ERR,
 		"Numrec values of last two get discovery log page not equal\n");
 		ret = -EBADSLT;
 		break;
 	default:
-		fprintf(stderr, "Get discovery log page failed: %d\n", ret);
+		log(LOG_ERR, "Get discovery log page failed: %d\n", ret);
 		break;
 	}
 
@@ -1359,7 +1362,7 @@ static int discover_from_conf_file(const char *desc, char *argstr,
 
 	f = fopen(PATH_NVMF_DISC, "r");
 	if (f == NULL) {
-		fprintf(stderr, "No discover params given and no %s conf\n",
+		log(LOG_ERR, "No discover params given and no %s conf\n",
 			PATH_NVMF_DISC);
 		return -EINVAL;
 	}
@@ -1370,14 +1373,14 @@ static int discover_from_conf_file(const char *desc, char *argstr,
 
 		args = strdup(line);
 		if (!args) {
-			fprintf(stderr, "failed to strdup args\n");
+			log(LOG_ERR, "failed to strdup args\n");
 			ret = -ENOMEM;
 			goto out;
 		}
 
 		argv = calloc(MAX_DISC_ARGS, BUF_SIZE);
 		if (!argv) {
-			fprintf(stderr, "failed to allocate argv vector\n");
+			log(LOG_ERR, "failed to allocate argv vector\n");
 			free(args);
 			ret = -ENOMEM;
 			goto out;
@@ -1428,6 +1431,7 @@ int fabrics_discover(const char *desc, int argc, char **argv, bool connect)
 {
 	char argstr[BUF_SIZE];
 	int ret;
+	bool quiet = false;
 
 	OPT_ARGS(opts) = {
 		OPT_LIST("transport",      't', &cfg.transport,       "transport type"),
@@ -1449,7 +1453,7 @@ int fabrics_discover(const char *desc, int argc, char **argv, bool connect)
 		OPT_INT("nr-poll-queues",  'P', &cfg.nr_poll_queues,  "number of poll queues to use (default 0)"),
 		OPT_INT("queue-size",      'Q', &cfg.queue_size,      "number of io queue elements to use (default 128)"),
 		OPT_FLAG("persistent",     'p', &cfg.persistent,      "persistent discovery connection"),
-		OPT_FLAG("quiet",          'S', &cfg.quiet,           "suppress already connected errors"),
+		OPT_FLAG("quiet",          'S', &quiet,               "suppress already connected errors"),
 		OPT_FLAG("matching",       'm', &cfg.matching_only,   "connect only records matching the traddr"),
 		OPT_END()
 	};
@@ -1459,6 +1463,9 @@ int fabrics_discover(const char *desc, int argc, char **argv, bool connect)
 	if (ret)
 		goto out;
 
+	if (quiet)
+		log_level = LOG_WARNING;
+
 	if (cfg.device && !strcmp(cfg.device, "none"))
 		cfg.device = NULL;
 
@@ -1534,7 +1541,7 @@ int fabrics_connect(const char *desc, int argc, char **argv)
 		goto out;
 
 	if (!cfg.nqn) {
-		fprintf(stderr, "need a -n argument\n");
+		log(LOG_ERR, "need a -n argument\n");
 		ret = -EINVAL;
 		goto out;
 	}
@@ -1572,7 +1579,7 @@ static int disconnect_subsys(char *nqn, char *ctrl)
 
 	fd = open(sysfs_nqn_path, O_RDONLY);
 	if (fd < 0) {
-		fprintf(stderr, "Failed to open %s: %s\n",
+		log(LOG_ERR, "Failed to open %s: %s\n",
 				sysfs_nqn_path, strerror(errno));
 		goto free;
 	}
@@ -1646,7 +1653,7 @@ int fabrics_disconnect(const char *desc, int argc, char **argv)
 		goto out;
 
 	if (!cfg.nqn && !cfg.device) {
-		fprintf(stderr, "need a -n or -d argument\n");
+		log(LOG_ERR, "need a -n or -d argument\n");
 		ret = -EINVAL;
 		goto out;
 	}
@@ -1654,7 +1661,7 @@ int fabrics_disconnect(const char *desc, int argc, char **argv)
 	if (cfg.nqn) {
 		ret = disconnect_by_nqn(cfg.nqn);
 		if (ret < 0)
-			fprintf(stderr, "Failed to disconnect by NQN: %s\n",
+			log(LOG_ERR, "Failed to disconnect by NQN: %s\n",
 				cfg.nqn);
 		else {
 			printf("NQN:%s disconnected %d controller(s)\n", cfg.nqn, ret);
@@ -1665,7 +1672,7 @@ int fabrics_disconnect(const char *desc, int argc, char **argv)
 	if (cfg.device) {
 		ret = disconnect_by_device(cfg.device);
 		if (ret)
-			fprintf(stderr,
+			log(LOG_ERR,
 				"Failed to disconnect by device name: %s\n",
 				cfg.device);
 	}
@@ -1689,7 +1696,7 @@ int fabrics_disconnect_all(const char *desc, int argc, char **argv)
 
 	err = scan_subsystems(&t, NULL, 0, NULL);
 	if (err) {
-		fprintf(stderr, "Failed to scan namespaces\n");
+		log(LOG_ERR, "Failed to scan namespaces\n");
 		goto out;
 	}
 
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:33:00 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:33:00 +0100
Subject: [PATCH 11/35] monitor: add option -A / --autoconnect
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-12-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

With this option, the monitor will try to connect to newly discovered
controllers.

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 monitor.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/monitor.c b/monitor.c
index a7afa1c..ecf3be2 100644
--- a/monitor.c
+++ b/monitor.c
@@ -31,6 +31,10 @@
 #define LOG_FUNCNAME 1
 #include "log.h"
 
+static struct monitor_config {
+	bool autoconnect;
+} mon_cfg;
+
 static struct udev *udev;
 
 static void close_ptr(int *p)
@@ -177,6 +181,7 @@ static int monitor_parse_opts(const char *desc, int argc, char **argv)
 	bool debug = false;
 	int ret;
 	OPT_ARGS(opts) = {
+		OPT_FLAG("autoconnect",    'A', &mon_cfg.autoconnect, "automatically connect newly discovered controllers"),
 		OPT_FLAG("silent",         'S', &quiet,               "log level: silent"),
 		OPT_FLAG("verbose",        'v', &verbose,             "log level: verbose"),
 		OPT_FLAG("debug",          'D', &debug,               "log level: debug"),
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:33:01 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:33:01 +0100
Subject: [PATCH 12/35] monitor: add helpers for __attribute__((cleanup))
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-13-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

__attribute__((cleanup)) is very helpful but ugly. Try to avoid
defining lots of cleanup functions with these macros.

Usage: to declare an auto-cleanup variable of type (some_type *),
write

CLEANUP_FUNC(some_type)

void some_func(void)
{
        CLEANUP(some_type, varname) = NULL;
	...
}

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 common.h | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/common.h b/common.h
index 1c214a4..9386ec5 100644
--- a/common.h
+++ b/common.h
@@ -12,4 +12,16 @@
 #define __stringify_1(x...) #x
 #define __stringify(x...)  __stringify_1(x)
 
+#define CLEANUP_FUNC(type) \
+static void __cleanup_ ## type ##_p(type ** __p) \
+{						 \
+	if (*__p) {				 \
+		free(*__p);			 \
+		*__p = NULL;			 \
+	}					 \
+}
+
+#define CLEANUP(__t, __v) \
+	__t *__v __attribute__((cleanup(__cleanup_ ## __t ## _p)))
+
 #endif
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:33:05 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:33:05 +0100
Subject: [PATCH 16/35] monitor: reset children's signal disposition
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-17-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 monitor.c | 30 ++++++++++++++++++++++++++++--
 1 file changed, 28 insertions(+), 2 deletions(-)

diff --git a/monitor.c b/monitor.c
index 69c8333..9375a14 100644
--- a/monitor.c
+++ b/monitor.c
@@ -100,6 +100,8 @@ static void monitor_int_handler(int sig)
 	must_exit = 1;
 }
 
+static sigset_t orig_sigmask;
+
 static int monitor_init_signals(void)
 {
 	sigset_t mask;
@@ -110,7 +112,7 @@ static int monitor_init_signals(void)
 	 * for events.
 	 */
 	sigfillset(&mask);
-	if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
+	if (sigprocmask(SIG_BLOCK, &mask, &orig_sigmask) == -1)
 		return -errno;
 	if (sigaction(SIGTERM, &sa, NULL) == -1)
 		return -errno;
@@ -119,6 +121,26 @@ static int monitor_init_signals(void)
 	return 0;
 }
 
+static int child_reset_signals(void)
+{
+	int err = 0;
+	struct sigaction sa = { .sa_handler = SIG_DFL, };
+
+	if (sigaction(SIGTERM, &sa, NULL) == -1)
+		err = errno;
+	if (sigaction(SIGINT, &sa, NULL) == -1 && !err)
+		err = errno;
+	if (sigaction(SIGCHLD, &sa, NULL) == -1 && !err)
+		err = errno;
+
+	if (sigprocmask(SIG_SETMASK, &orig_sigmask, NULL) == -1 && !err)
+		err = errno;
+
+	if (err)
+		log(LOG_ERR, "error resetting signal handlers and mask\n");
+	return -err;
+}
+
 static int monitor_get_fc_uev_props(struct udev_device *ud,
 				    char *traddr, size_t tra_sz,
 				    char *host_traddr, size_t htra_sz)
@@ -176,8 +198,12 @@ static int monitor_discovery(char *transport, char *traddr, char *trsvcid,
 	if (pid == -1) {
 		log(LOG_ERR, "failed to fork discovery task: %m");
 		return -errno;
-	} else if (pid > 0)
+	} else if (pid > 0) {
+		log(LOG_DEBUG, "started discovery task %ld\n", (long)pid);
 		return 0;
+	}
+
+	child_reset_signals();
 
 	log(LOG_NOTICE, "starting %s discovery for %s==>%s(%s)\n",
 	    transport, host_traddr, traddr, trsvcid ? trsvcid : "none");
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:33:04 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:33:04 +0100
Subject: [PATCH 15/35] monitor: implement handling of nvme AEN events
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-16-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

This is very similar to fc_udev_device events, except that we
have different udev properties and must use trsvcid.

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 monitor.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 70 insertions(+)

diff --git a/monitor.c b/monitor.c
index 6547265..69c8333 100644
--- a/monitor.c
+++ b/monitor.c
@@ -214,6 +214,74 @@ static void monitor_handle_fc_uev(struct udev_device *ud)
 	monitor_discovery("fc", traddr, NULL, host_traddr);
 }
 
+static int monitor_get_nvme_uev_props(struct udev_device *ud,
+				      char *transport, size_t tr_sz,
+				      char *traddr, size_t tra_sz,
+				      char *trsvcid, size_t trs_sz,
+				      char *host_traddr, size_t htra_sz)
+{
+	const char *sysname = udev_device_get_sysname(ud);
+	bool aen_disc = false;
+	struct udev_list_entry *entry;
+
+	entry = udev_device_get_properties_list_entry(ud);
+	if (!entry) {
+		log(LOG_NOTICE, "%s: emtpy properties list\n", sysname);
+		return -ENOENT;
+	}
+
+	*transport = *traddr = *trsvcid = *host_traddr = '\0';
+	for (; entry; entry = udev_list_entry_get_next(entry)) {
+		const char *name = udev_list_entry_get_name(entry);
+
+		if (!strcmp(name, "NVME_AEN") &&
+		    !strcmp(udev_list_entry_get_value(entry), "0x70f002"))
+				aen_disc = true;
+		else if (!strcmp(name, "NVME_TRTYPE"))
+			memccpy(transport, udev_list_entry_get_value(entry),
+				'\0', tr_sz);
+		else if (!strcmp(name, "NVME_TRADDR"))
+			memccpy(traddr, udev_list_entry_get_value(entry),
+				'\0', htra_sz);
+		else if (!strcmp(name, "NVME_TRSVCID"))
+			memccpy(trsvcid, udev_list_entry_get_value(entry),
+				'\0', trs_sz);
+		else if (!strcmp(name, "NVME_HOST_TRADDR"))
+			memccpy(host_traddr, udev_list_entry_get_value(entry),
+				'\0', tra_sz);
+	}
+	if (!aen_disc) {
+		log(LOG_DEBUG, "%s: not a \"discovery log changed\" AEN, ignoring event\n",
+		    sysname);
+		return -EINVAL;
+	}
+
+	if (!*traddr || !*transport) {
+		log(LOG_WARNING, "%s: transport properties missing\n", sysname);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void monitor_handle_nvme_uev(struct udev_device *ud)
+{
+	char traddr[NVMF_TRADDR_SIZE], host_traddr[NVMF_TRADDR_SIZE];
+	char trsvcid[NVMF_TRSVCID_SIZE], transport[5];
+
+	if (strcmp(udev_device_get_action(ud), "change"))
+		return;
+
+	if (monitor_get_nvme_uev_props(ud, transport, sizeof(transport),
+				       traddr, sizeof(traddr),
+				       trsvcid, sizeof(trsvcid),
+				       host_traddr, sizeof(host_traddr)))
+		return;
+
+	monitor_discovery(transport, traddr,
+			  strcmp(trsvcid, "none") ? trsvcid : NULL, host_traddr);
+}
+
 static void monitor_handle_udevice(struct udev_device *ud)
 {
 	const char *subsys  = udev_device_get_subsystem(ud);
@@ -226,6 +294,8 @@ static void monitor_handle_udevice(struct udev_device *ud)
 	}
 	if (!strcmp(subsys, "fc"))
 		monitor_handle_fc_uev(ud);
+	else if (!strcmp(subsys, "nvme"))
+		monitor_handle_nvme_uev(ud);
 }
 
 static void monitor_handle_uevents(struct udev_monitor *monitor)
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:33:07 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:33:07 +0100
Subject: [PATCH 18/35] monitor: add "--persistent/-p" flag
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-19-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

Without this flag, AENs on created controllers won't be received.
While --persistent is probably the behavior most users will want,
it has to be explicitly activated, to be consistent with the
connect-all command.

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 monitor.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/monitor.c b/monitor.c
index 8db40e6..419c5f5 100644
--- a/monitor.c
+++ b/monitor.c
@@ -487,6 +487,7 @@ static int monitor_parse_opts(const char *desc, int argc, char **argv)
 
 	OPT_ARGS(opts) = {
 		OPT_FLAG("autoconnect",    'A', &mon_cfg.autoconnect, "automatically connect newly discovered controllers"),
+		OPT_FLAG("persistent",     'p', &cfg.persistent,      "persistent discovery connections"),
 		OPT_FLAG("silent",         'S', &quiet,               "log level: silent"),
 		OPT_FLAG("verbose",        'v', &verbose,             "log level: verbose"),
 		OPT_FLAG("debug",          'D', &debug,               "log level: debug"),
@@ -514,6 +515,10 @@ static int monitor_parse_opts(const char *desc, int argc, char **argv)
 			ret = 0;
 		}
 	}
+
+	if (cfg.persistent && !cfg.keep_alive_tmo)
+		cfg.keep_alive_tmo = NVMF_DEF_DISC_TMO;
+
 	return ret;
 }
 
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:33:03 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:33:03 +0100
Subject: [PATCH 14/35] monitor: implement handling of fc_udev_device
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-15-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

The reason we fork off discovery tasks is two-fold: Firstly, we'd
otherwise be forced to make all discovery connections sequentially,
which would be slow, as connecting controllers can block on
the order of seconds even in successful cases.

Secondly, this allows us to use the some static variables like
cfg and tracked_ctrls in the discovery code path. Without forking,
we'd have to re-write much more code in fabrics.c. In general,
the alternative to forking would be creating threads, but the
that would probably require a large rewrite of our code base.

A single-threaded server that forks off the actual discovery makes
most sense at this point.

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 monitor.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 107 insertions(+), 3 deletions(-)

diff --git a/monitor.c b/monitor.c
index 2a906db..6547265 100644
--- a/monitor.c
+++ b/monitor.c
@@ -30,7 +30,9 @@
 
 #include "common.h"
 #include "nvme-status.h"
+#include "nvme.h"
 #include "util/argconfig.h"
+#include "fabrics.h"
 #include "monitor.h"
 #define LOG_FUNCNAME 1
 #include "log.h"
@@ -117,11 +119,113 @@ static int monitor_init_signals(void)
 	return 0;
 }
 
+static int monitor_get_fc_uev_props(struct udev_device *ud,
+				    char *traddr, size_t tra_sz,
+				    char *host_traddr, size_t htra_sz)
+{
+	const char *sysname = udev_device_get_sysname(ud);
+	const char *tra = NULL, *host_tra = NULL;
+	bool fc_event_seen = false;
+	struct udev_list_entry *entry;
+
+	entry = udev_device_get_properties_list_entry(ud);
+	if (!entry) {
+		log(LOG_NOTICE, "%s: emtpy properties list\n", sysname);
+		return -ENOENT;
+	}
+
+	for (; entry; entry = udev_list_entry_get_next(entry)) {
+		const char *name = udev_list_entry_get_name(entry);
+
+		if (!strcmp(name, "FC_EVENT") &&
+		    !strcmp(udev_list_entry_get_value(entry), "nvmediscovery"))
+				fc_event_seen = true;
+		else if (!strcmp(name, "NVMEFC_HOST_TRADDR"))
+			host_tra = udev_list_entry_get_value(entry);
+		else if (!strcmp(name, "NVMEFC_TRADDR"))
+			tra = udev_list_entry_get_value(entry);
+	}
+	if (!fc_event_seen) {
+		log(LOG_DEBUG, "%s: FC_EVENT property missing or unsupported\n",
+		    sysname);
+		return -EINVAL;
+	}
+	if (!tra || !host_tra) {
+		log(LOG_WARNING, "%s: transport properties missing\n", sysname);
+		return -EINVAL;
+	}
+
+	if (!memccpy(traddr, tra, '\0', tra_sz) ||
+	    !memccpy(host_traddr, host_tra, '\0', htra_sz)) {
+		log(LOG_ERR, "traddr (%zu) or host_traddr (%zu) overflow\n",
+		    strlen(traddr), strlen(host_traddr));
+		return -ENAMETOOLONG;
+	}
+
+	return 0;
+}
+
+static int monitor_discovery(char *transport, char *traddr, char *trsvcid,
+			     char *host_traddr)
+{
+	char argstr[BUF_SIZE];
+	pid_t pid;
+	int rc;
+
+	pid = fork();
+	if (pid == -1) {
+		log(LOG_ERR, "failed to fork discovery task: %m");
+		return -errno;
+	} else if (pid > 0)
+		return 0;
+
+	log(LOG_NOTICE, "starting %s discovery for %s==>%s(%s)\n",
+	    transport, host_traddr, traddr, trsvcid ? trsvcid : "none");
+	cfg.nqn = NVME_DISC_SUBSYS_NAME;
+	cfg.transport = transport;
+	cfg.traddr = traddr;
+	cfg.trsvcid = trsvcid;
+	cfg.host_traddr = host_traddr;
+	/* Without the following, the kernel returns EINVAL */
+	cfg.tos = -1;
+
+	rc = build_options(argstr, sizeof(argstr), true);
+	log(LOG_DEBUG, "%s\n", argstr);
+	rc = do_discover(argstr, mon_cfg.autoconnect);
+
+	exit(-rc);
+	/* not reached */
+	return rc;
+}
+
+static void monitor_handle_fc_uev(struct udev_device *ud)
+{
+	const char *action = udev_device_get_action(ud);
+	const char *sysname = udev_device_get_sysname(ud);
+	char traddr[NVMF_TRADDR_SIZE], host_traddr[NVMF_TRADDR_SIZE];
+
+	if (strcmp(action, "change") || strcmp(sysname, "fc_udev_device"))
+		return;
+
+	if (monitor_get_fc_uev_props(ud, traddr, sizeof(traddr),
+				     host_traddr, sizeof(host_traddr)))
+		return;
+
+	monitor_discovery("fc", traddr, NULL, host_traddr);
+}
+
 static void monitor_handle_udevice(struct udev_device *ud)
 {
-	log(LOG_INFO, "uevent: %s %s\n",
-		udev_device_get_action(ud),
-		udev_device_get_sysname(ud));
+	const char *subsys  = udev_device_get_subsystem(ud);
+
+	if (log_level >= LOG_INFO) {
+		const char *action = udev_device_get_action(ud);
+		const char *syspath = udev_device_get_syspath(ud);
+
+		log(LOG_INFO, "%s %s\n", action, syspath);
+	}
+	if (!strcmp(subsys, "fc"))
+		monitor_handle_fc_uev(ud);
 }
 
 static void monitor_handle_uevents(struct udev_monitor *monitor)
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:33:06 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:33:06 +0100
Subject: [PATCH 17/35] monitor: handle SIGCHLD for terminated child processes
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-18-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 monitor.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 48 insertions(+), 2 deletions(-)

diff --git a/monitor.c b/monitor.c
index 9375a14..8db40e6 100644
--- a/monitor.c
+++ b/monitor.c
@@ -26,6 +26,8 @@
 #include <limits.h>
 #include <syslog.h>
 #include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
 #include <sys/epoll.h>
 
 #include "common.h"
@@ -100,6 +102,13 @@ static void monitor_int_handler(int sig)
 	must_exit = 1;
 }
 
+static sig_atomic_t got_sigchld;
+
+static void monitor_chld_handler(int sig)
+{
+	got_sigchld = 1;
+}
+
 static sigset_t orig_sigmask;
 
 static int monitor_init_signals(void)
@@ -118,6 +127,9 @@ static int monitor_init_signals(void)
 		return -errno;
 	if (sigaction(SIGINT, &sa, NULL) == -1)
 		return -errno;
+	sa.sa_handler = monitor_chld_handler;
+	if (sigaction(SIGCHLD, &sa, NULL) == -1)
+		return -errno;
 	return 0;
 }
 
@@ -336,6 +348,34 @@ static void monitor_handle_uevents(struct udev_monitor *monitor)
 	}
 }
 
+static void handle_sigchld(void)
+{
+	while (true) {
+		int wstatus;
+		pid_t pid;
+
+		pid = waitpid(-1, &wstatus, WNOHANG);
+		switch(pid) {
+		case -1:
+			if (errno != ECHILD)
+				log(LOG_ERR, "error in waitpid: %m\n");
+			return;
+		case 0:
+			return;
+		default:
+			break;
+		}
+		if (!WIFEXITED(wstatus))
+			log(LOG_WARNING, "child %ld didn't exit normally\n",
+			    (long)pid);
+		else if (WEXITSTATUS(wstatus) != 0)
+			log(LOG_NOTICE, "child %ld exited with status \"%s\"\n",
+			    (long)pid, strerror(WEXITSTATUS(wstatus)));
+		else
+			log(LOG_DEBUG, "child %ld exited normally\n", (long)pid);
+	};
+}
+
 #define MAX_EVENTS 1
 static int monitor_main_loop(struct udev_monitor *monitor)
 {
@@ -357,13 +397,19 @@ static int monitor_main_loop(struct udev_monitor *monitor)
 	sigfillset(&ep_mask);
 	sigdelset(&ep_mask, SIGTERM);
 	sigdelset(&ep_mask, SIGINT);
+	sigdelset(&ep_mask, SIGCHLD);
 	while (1) {
 		int rc, i;
 
 		rc = epoll_pwait(ep_fd, events, MAX_EVENTS, -1, &ep_mask);
 		if (rc == -1 && errno == EINTR) {
-			log(LOG_NOTICE, "monitor: exit signal received\n");
-			return 0;
+			if (must_exit) {
+				log(LOG_NOTICE, "monitor: exit signal received\n");
+				return 0;
+			} else if (got_sigchld) {
+				got_sigchld = 0;
+				handle_sigchld();
+			}
 		} else if (rc == -1) {
 			log(LOG_ERR, "monitor: epoll_wait: %m\n");
 			return -errno;
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:33:02 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:33:02 +0100
Subject: [PATCH 13/35] monitor: disable nvmf-autoconnect udev rules in
 autoconnect mode
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-14-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

If autoconnect is enabled, disable the respective udev rules
by symlinking /run/udev/rules.d to /dev/null, in order to avoid
the connections being set up by the monitor and the udev workers
at the same time. This is probably the preferred mode of operation
for the monitor.

Users can override this by copying 70-nvmf-autoconnect.rules
from /usr/lib/udev/rules.d to /etc/udev/rules.d (/etc/udev/rules.d
takes precedence over /run/udev/rules.d).

If the symlink can't be created for some reason, autoconnect will
be disabled. There is  only one exception: If
/run/udev/rules.d/70-nvmf-autoconnect.rules already points to
/dev/null at startup, autoconnect can be left on, but the symlink
isn't removed on exit.

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 monitor.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 73 insertions(+), 2 deletions(-)

diff --git a/monitor.c b/monitor.c
index ecf3be2..2a906db 100644
--- a/monitor.c
+++ b/monitor.c
@@ -17,14 +17,18 @@
 
 #include <stddef.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <unistd.h>
 #include <errno.h>
 #include <libudev.h>
 #include <signal.h>
 #include <time.h>
+#include <limits.h>
 #include <syslog.h>
+#include <sys/stat.h>
 #include <sys/epoll.h>
 
+#include "common.h"
 #include "nvme-status.h"
 #include "util/argconfig.h"
 #include "monitor.h"
@@ -33,6 +37,7 @@
 
 static struct monitor_config {
 	bool autoconnect;
+	bool skip_udev_on_exit;
 } mon_cfg;
 
 static struct udev *udev;
@@ -45,6 +50,8 @@ static void close_ptr(int *p)
 	}
 }
 
+CLEANUP_FUNC(char)
+
 static void cleanup_monitor(struct udev_monitor **pmon)
 {
 	if (*pmon) {
@@ -174,12 +181,64 @@ static int monitor_main_loop(struct udev_monitor *monitor)
 	return ret;
 }
 
+static const char autoconnect_rules[] = "/run/udev/rules.d/70-nvmf-autoconnect.rules";
+
+static int monitor_disable_udev_rules(void)
+{
+	CLEANUP(char, path) = strdup(autoconnect_rules);
+	char *s1, *s2;
+	int rc;
+
+	if (!path)
+		return -ENOMEM;
+
+	s2 = strrchr(path, '/');
+	for (s1 = s2 - 1; s1 > path && *s1 != '/'; s1--);
+
+	*s2 = *s1 = '\0';
+	rc = mkdir(path, 0755);
+	if (rc == 0 || errno == EEXIST) {
+		*s1 = '/';
+		rc = mkdir(path, 0755);
+		if (rc == 0 || errno == EEXIST) {
+			*s2 = '/';
+			rc = symlink("/dev/null", path);
+		}
+	}
+	if (rc) {
+		if (errno == EEXIST) {
+			char target[PATH_MAX];
+
+			if (readlink(path, target, sizeof(target)) != -1 &&
+			    !strcmp(target, "/dev/null")) {
+				log(LOG_INFO,
+				    "symlink %s -> /dev/null exists already\n",
+				    autoconnect_rules);
+				return 1;
+			}
+		}
+		log(LOG_ERR, "error creating %s: %m\n", autoconnect_rules);
+	} else
+		log(LOG_INFO, "created %s\n", autoconnect_rules);
+
+	return rc ? (errno ? -errno : -EIO) : 0;
+}
+
+static void monitor_enable_udev_rules(void)
+{
+	if (unlink(autoconnect_rules) == -1 && errno != ENOENT)
+		log(LOG_ERR, "error removing %s: %m\n", autoconnect_rules);
+	else
+		log(LOG_INFO, "removed %s\n", autoconnect_rules);
+}
+
 static int monitor_parse_opts(const char *desc, int argc, char **argv)
 {
 	bool quiet = false;
 	bool verbose = false;
 	bool debug = false;
-	int ret;
+	int ret = 0;
+
 	OPT_ARGS(opts) = {
 		OPT_FLAG("autoconnect",    'A', &mon_cfg.autoconnect, "automatically connect newly discovered controllers"),
 		OPT_FLAG("silent",         'S', &quiet,               "log level: silent"),
@@ -198,7 +257,17 @@ static int monitor_parse_opts(const char *desc, int argc, char **argv)
 		log_level = LOG_INFO;
 	if (debug)
 		log_level = LOG_DEBUG;
-
+	if (mon_cfg.autoconnect) {
+		ret = monitor_disable_udev_rules();
+		if (ret < 0) {
+			mon_cfg.autoconnect = false;
+			log(LOG_WARNING, "autoconnect disabled\n");
+			ret = 0;
+		} else if (ret > 0) {
+			mon_cfg.skip_udev_on_exit = true;
+			ret = 0;
+		}
+	}
 	return ret;
 }
 
@@ -221,6 +290,8 @@ int aen_monitor(const char *desc, int argc, char **argv)
 		udev_monitor_unref(monitor);
 	}
 	udev = udev_unref(udev);
+	if (mon_cfg.autoconnect && !mon_cfg.skip_udev_on_exit)
+		monitor_enable_udev_rules();
 out:
 	return nvme_status_to_errno(ret, true);
 }
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:33:09 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:33:09 +0100
Subject: [PATCH 20/35] fabrics: export arg_str(), parse_conn_arg(),
 and remove_ctrl()
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-21-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

These functions are used by the monitor functionality that will
be added in follow-up commits.

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 fabrics.c | 6 +++---
 fabrics.h | 4 ++++
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/fabrics.c b/fabrics.c
index e3d2a3a..e2629d5 100644
--- a/fabrics.c
+++ b/fabrics.c
@@ -102,7 +102,7 @@ static const match_table_t opt_tokens = {
 	{ OPT_ERR,		NULL		},
 };
 
-static const char *arg_str(const char * const *strings,
+const char *arg_str(const char * const *strings,
 		size_t array_size, size_t idx)
 {
 	if (idx < array_size && strings[idx])
@@ -208,7 +208,7 @@ int do_discover(char *argstr, bool connect);
  * If field found, return string containing field value. If field
  * not found, return an empty string.
  */
-static char *parse_conn_arg(char *conargs, const char delim, const char *field)
+char *parse_conn_arg(char *conargs, const char delim, const char *field)
 {
 	char *s, *e;
 	size_t cnt;
@@ -476,7 +476,7 @@ out:
 	return ret;
 }
 
-static int remove_ctrl(int instance)
+int remove_ctrl(int instance)
 {
 	char *sysfs_path;
 	int ret;
diff --git a/fabrics.h b/fabrics.h
index 1dfbd67..ddc7423 100644
--- a/fabrics.h
+++ b/fabrics.h
@@ -12,6 +12,8 @@ extern int fabrics_disconnect_all(const char *desc, int argc, char **argv);
 
 /* Symbols used by monitor.c */
 
+const char *arg_str(const char * const *strings, size_t array_size, size_t idx);
+
 struct config {
 	const char *nqn;
 	const char *transport;
@@ -44,5 +46,7 @@ extern struct config cfg;
 int build_options(char *argstr, int max_len, bool discover);
 int do_discover(char *argstr, bool connect);
 int ctrl_instance(const char *device);
+char *parse_conn_arg(char *conargs, const char delim, const char *field);
+int remove_ctrl(int instance);
 
 #endif
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:33:08 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:33:08 +0100
Subject: [PATCH 19/35] fabrics: use "const char *" in struct config
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-20-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

This is easily done, and allows passing in some const char* pointers
that would otherwise need to be strdup()d first.

constifying cfg->device requires changes in the ctrl_instance()
function, because basename() can't be used.

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 fabrics.c | 23 ++++++++++++++---------
 fabrics.h | 17 +++++++++--------
 2 files changed, 23 insertions(+), 17 deletions(-)

diff --git a/fabrics.c b/fabrics.c
index c1a4bb5..e3d2a3a 100644
--- a/fabrics.c
+++ b/fabrics.c
@@ -252,17 +252,22 @@ empty_field:
 	return strdup("\0");
 }
 
-static int ctrl_instance(char *device)
+int ctrl_instance(const char *device)
 {
 	char d[64];
+	const char *p;
 	int ret, instance;
 
-	device = basename(device);
-	ret = sscanf(device, "nvme%d", &instance);
+	p = strrchr(device, '/');
+	if (p == NULL)
+		p = device;
+	else
+		p++;
+	ret = sscanf(p, "nvme%d", &instance);
 	if (ret <= 0)
 		return -EINVAL;
 	if (snprintf(d, sizeof(d), "nvme%d", instance) <= 0 ||
-	    strcmp(device, d))
+	    strcmp(p, d))
 		return -EINVAL;
 	return instance;
 }
@@ -273,7 +278,7 @@ static int ctrl_instance(char *device)
  * given.
  * Return true/false based on whether it matches
  */
-static bool ctrl_matches_connectargs(char *name, struct connect_args *args)
+static bool ctrl_matches_connectargs(const char *name, struct connect_args *args)
 {
 	struct connect_args cargs;
 	bool found = false;
@@ -815,7 +820,7 @@ add_int_argument(char **argstr, int *max_len, char *arg_str, int arg,
 }
 
 static int
-add_argument(char **argstr, int *max_len, char *arg_str, char *arg)
+add_argument(char **argstr, int *max_len, char *arg_str, const char *arg)
 {
 	int len;
 
@@ -1541,7 +1546,7 @@ static int scan_sys_nvme_filter(const struct dirent *d)
 /*
  * Returns 1 if disconnect occurred, 0 otherwise.
  */
-static int disconnect_subsys(char *nqn, char *ctrl)
+static int disconnect_subsys(const char *nqn, char *ctrl)
 {
 	char *sysfs_nqn_path = NULL, *sysfs_del_path = NULL;
 	char subsysnqn[NVMF_NQN_SIZE] = {};
@@ -1579,7 +1584,7 @@ static int disconnect_subsys(char *nqn, char *ctrl)
 /*
  * Returns the number of controllers successfully disconnected.
  */
-static int disconnect_by_nqn(char *nqn)
+static int disconnect_by_nqn(const char *nqn)
 {
 	struct dirent **devices = NULL;
 	int i, n, ret = 0;
@@ -1601,7 +1606,7 @@ static int disconnect_by_nqn(char *nqn)
 	return ret;
 }
 
-static int disconnect_by_device(char *device)
+static int disconnect_by_device(const char *device)
 {
 	int instance;
 
diff --git a/fabrics.h b/fabrics.h
index ce965a3..1dfbd67 100644
--- a/fabrics.h
+++ b/fabrics.h
@@ -13,13 +13,13 @@ extern int fabrics_disconnect_all(const char *desc, int argc, char **argv);
 /* Symbols used by monitor.c */
 
 struct config {
-	char *nqn;
-	char *transport;
-	char *traddr;
-	char *trsvcid;
-	char *host_traddr;
-	char *hostnqn;
-	char *hostid;
+	const char *nqn;
+	const char *transport;
+	const char *traddr;
+	const char *trsvcid;
+	const char *host_traddr;
+	const char *hostnqn;
+	const char *hostid;
 	int  nr_io_queues;
 	int  nr_write_queues;
 	int  nr_poll_queues;
@@ -29,7 +29,7 @@ struct config {
 	int  ctrl_loss_tmo;
 	int  tos;
 	char *raw;
-	char *device;
+	const char *device;
 	int  duplicate_connect;
 	int  disable_sqflow;
 	int  hdr_digest;
@@ -43,5 +43,6 @@ extern struct config cfg;
 
 int build_options(char *argstr, int max_len, bool discover);
 int do_discover(char *argstr, bool connect);
+int ctrl_instance(const char *device);
 
 #endif
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:33:12 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:33:12 +0100
Subject: [PATCH 23/35] monitor: handle restart of pending discoveries
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-24-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

If a new discovery event is received while a discovery task is
running, no new task should be started in parallel to the previous
one. Rather, we should note that another event has happened,
and restart the discovery after the current task has finished.

There is no need to remember more than one pending discovery.

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 monitor.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 49 insertions(+), 9 deletions(-)

diff --git a/monitor.c b/monitor.c
index 419c5f5..b44ff7a 100644
--- a/monitor.c
+++ b/monitor.c
@@ -36,6 +36,7 @@
 #include "util/argconfig.h"
 #include "fabrics.h"
 #include "monitor.h"
+#include "conn-db.h"
 #define LOG_FUNCNAME 1
 #include "log.h"
 
@@ -199,12 +200,22 @@ static int monitor_get_fc_uev_props(struct udev_device *ud,
 	return 0;
 }
 
-static int monitor_discovery(char *transport, char *traddr, char *trsvcid,
-			     char *host_traddr)
+static int monitor_discovery(const char *transport, const char *traddr,
+			     const char *trsvcid, const char *host_traddr)
 {
 	char argstr[BUF_SIZE];
 	pid_t pid;
-	int rc;
+	int rc, db_rc;
+	struct nvme_connection *co = NULL;
+
+	db_rc = conndb_add(transport, traddr, trsvcid, host_traddr, &co);
+	if (db_rc != 0 && db_rc != -EEXIST)
+		return db_rc;
+
+	if (co->status == CS_DISC_RUNNING) {
+		co->discovery_pending = 1;
+		return -EAGAIN;
+	}
 
 	pid = fork();
 	if (pid == -1) {
@@ -212,17 +223,26 @@ static int monitor_discovery(char *transport, char *traddr, char *trsvcid,
 		return -errno;
 	} else if (pid > 0) {
 		log(LOG_DEBUG, "started discovery task %ld\n", (long)pid);
+
+		co->discovery_pending = 0;
+		co->status = CS_DISC_RUNNING;
+		co->discovery_task = pid;
+
 		return 0;
 	}
 
 	child_reset_signals();
 
-	log(LOG_NOTICE, "starting %s discovery for %s==>%s(%s)\n",
-	    transport, host_traddr, traddr, trsvcid ? trsvcid : "none");
+	log(LOG_NOTICE, "starting discovery for <%s>: %s ==> %s(%s) in state %s\n",
+	    transport, host_traddr, traddr,
+	    trsvcid && *trsvcid ? trsvcid : "none",
+	    conn_status_str(co->status));
+
+
 	cfg.nqn = NVME_DISC_SUBSYS_NAME;
 	cfg.transport = transport;
 	cfg.traddr = traddr;
-	cfg.trsvcid = trsvcid;
+	cfg.trsvcid = trsvcid && *trsvcid ? trsvcid : NULL;
 	cfg.host_traddr = host_traddr;
 	/* Without the following, the kernel returns EINVAL */
 	cfg.tos = -1;
@@ -351,6 +371,7 @@ static void monitor_handle_uevents(struct udev_monitor *monitor)
 static void handle_sigchld(void)
 {
 	while (true) {
+	struct nvme_connection *co;
 		int wstatus;
 		pid_t pid;
 
@@ -365,14 +386,33 @@ static void handle_sigchld(void)
 		default:
 			break;
 		}
-		if (!WIFEXITED(wstatus))
+		co = conndb_find_by_pid(pid);
+		if (!co) {
+			log(LOG_ERR, "no connection found for discovery task %ld\n",
+			    (long)pid);
+			continue;
+		}
+		if (!WIFEXITED(wstatus)) {
 			log(LOG_WARNING, "child %ld didn't exit normally\n",
 			    (long)pid);
-		else if (WEXITSTATUS(wstatus) != 0)
+			co->status = CS_FAILED;
+		} else if (WEXITSTATUS(wstatus) != 0) {
 			log(LOG_NOTICE, "child %ld exited with status \"%s\"\n",
 			    (long)pid, strerror(WEXITSTATUS(wstatus)));
-		else
+			co->status = CS_FAILED;
+			co->did_discovery = 1;
+			co->discovery_result = WEXITSTATUS(wstatus);
+		} else {
 			log(LOG_DEBUG, "child %ld exited normally\n", (long)pid);
+			co->status = CS_ONLINE;
+			co->successful_discovery = co->did_discovery = 1;
+			co->discovery_result = 0;
+		}
+		if (co->discovery_pending) {
+			log(LOG_NOTICE, "new discovery pending - restarting\n");
+			monitor_discovery(co->transport, co->traddr,
+					  co->trsvcid, co->host_traddr);
+		}
 	};
 }
 
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:33:17 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:33:17 +0100
Subject: [PATCH 28/35] monitor: basic handling of add/remove uevents for nvme
 controllers
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-29-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

On add, we'd like to detect the creation of a discovery controller for a given
connection. More often than not, that doesn't work, because the controller
is still in "connecting" state when the uevent arrives, and reading subsysnqn
yields "(efault)".

This would need to be fixed by waiting for the connection to complete,
but doing this properly is currently out of scope. It's not really a big
problem, because without --persistent, the discovery controller will
be removed anyway, and with --persistent, we'll notice the discovery
controller as soon as it actually receives an AEN and generates an uevent.

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 monitor.c | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/monitor.c b/monitor.c
index e3fee55..e2c2568 100644
--- a/monitor.c
+++ b/monitor.c
@@ -155,6 +155,36 @@ static int child_reset_signals(void)
 	return -err;
 }
 
+static void monitor_handle_nvme_add(struct udev_device *ud)
+{
+	const char *syspath = udev_device_get_syspath(ud);
+	CLEANUP(char, subsysnqn) = NULL;
+	CLEANUP(char, state) = NULL;
+
+	if (!syspath)
+		return;
+	subsysnqn = nvme_get_ctrl_attr(syspath, "subsysnqn");
+	state = nvme_get_ctrl_attr(syspath, "state");
+	log(LOG_DEBUG, "add %s => %s [%s]\n", syspath, subsysnqn, state);
+}
+
+static void monitor_handle_nvme_remove(struct udev_device *ud)
+{
+	const char *sysname = udev_device_get_sysname(ud);
+	struct nvme_connection *co;
+
+	if (!sysname)
+		return;
+
+	co = conndb_find_by_ctrl(sysname);
+	if (co) {
+		log(LOG_DEBUG, "%s: connection discovery controller removed\n",
+		    sysname);
+		co->discovery_instance = -1;
+	}
+	return;
+}
+
 static int monitor_get_fc_uev_props(struct udev_device *ud,
 				    char *traddr, size_t tra_sz,
 				    char *host_traddr, size_t htra_sz)
@@ -353,6 +383,14 @@ static void monitor_handle_nvme_uev(struct udev_device *ud)
 	char traddr[NVMF_TRADDR_SIZE], host_traddr[NVMF_TRADDR_SIZE];
 	char trsvcid[NVMF_TRSVCID_SIZE], transport[5];
 
+	if (!strcmp(udev_device_get_action(ud), "remove")) {
+		monitor_handle_nvme_remove(ud);
+		return;
+	}
+	if (!strcmp(udev_device_get_action(ud), "add")) {
+		monitor_handle_nvme_add(ud);
+		return;
+	}
 	if (strcmp(udev_device_get_action(ud), "change"))
 		return;
 
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:33:20 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:33:20 +0100
Subject: [PATCH 31/35] completions: add completions for nvme monitor
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-32-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 completions/bash-nvme-completion.sh | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/completions/bash-nvme-completion.sh b/completions/bash-nvme-completion.sh
index d669e9b..9bf0da8 100644
--- a/completions/bash-nvme-completion.sh
+++ b/completions/bash-nvme-completion.sh
@@ -11,7 +11,7 @@ _cmds="list id-ctrl id-ns list-ns id-iocs create-ns delete-ns \
 	resv-report dsm flush compare read write write-zeroes \
 	write-uncor copy reset subsystem-reset show-regs discover \
 	connect-all connect disconnect version help \
-	intel lnvm memblaze list-subsys"
+	intel lnvm memblaze list-subsys monitor"
 
 nvme_list_opts () {
         local opts=""
@@ -231,6 +231,10 @@ nvme_list_opts () {
 		"disconnect")
 		opts+=" --nqn -n --device -d"
 			;;
+		"monitor")
+		opts+=" --autoconnect -A --persistent -p --startup -U \
+			--hostnqn= -q --verbose -v --clockstamps -C"
+			;;
 		"version")
 		opts+=""
 			;;
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:33:10 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:33:10 +0100
Subject: [PATCH 21/35] nvme-cli: add "list.h"
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-22-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

Adding "list.h" from multipath-tools, which got it from the kernel
long ago.

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 list.h | 365 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 365 insertions(+)
 create mode 100644 list.h

diff --git a/list.h b/list.h
new file mode 100644
index 0000000..ced021f
--- /dev/null
+++ b/list.h
@@ -0,0 +1,365 @@
+/*
+ * Copied from the Linux kernel source tree, version 2.6.0-test1.
+ *
+ * Licensed under the GPL v2 as per the whole kernel source tree.
+ *
+ */
+
+#ifndef _LIST_H
+#define _LIST_H
+
+#include <stddef.h>
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ *
+ * @ptr:	the pointer to the member.
+ * @type:	the type of the container struct this is embedded in.
+ * @member:	the name of the member within the struct.
+ *
+ */
+#define container_of_const(ptr, type, member) ({		\
+	const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
+	(const type *)( (const char *)__mptr - offsetof(type,member) );})
+
+#define container_of(ptr, type, member) ({		\
+	typeof( ((type *)0)->member ) *__mptr = (ptr);	\
+	(type *)( (char *)__mptr - offsetof(type,member) );})
+
+/*
+ * These are non-NULL pointers that will result in page faults
+ * under normal circumstances, used to verify that nobody uses
+ * non-initialized list entries.
+ */
+#define LIST_POISON1  ((void *) 0x00100100)
+#define LIST_POISON2  ((void *) 0x00200200)
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+	struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+	struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+	(ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+			      struct list_head *prev,
+			      struct list_head *next)
+{
+	next->prev = new;
+	new->next = next;
+	new->prev = prev;
+	prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+	next->prev = prev;
+	prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	entry->next = LIST_POISON1;
+	entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+	__list_del(list->prev, list->next);
+	list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+				  struct list_head *head)
+{
+	__list_del(list->prev, list->next);
+	list_add_tail(list, head);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(struct list_head *head)
+{
+	return head->next == head;
+}
+
+static inline void __list_splice(const struct list_head *list,
+				 struct list_head *prev,
+				 struct list_head *next)
+{
+	struct list_head *first = list->next;
+	struct list_head *last = list->prev;
+
+	first->prev = prev;
+	prev->next = first;
+
+	last->next = next;
+	next->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+	if (!list_empty(list))
+		__list_splice(list, head, head->next);
+}
+
+/**
+ * list_splice_tail - join two lists, each list being a queue
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice_tail(struct list_head *list,
+				    struct list_head *head)
+{
+	if (!list_empty(list))
+		__list_splice(list, head->prev, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+				    struct list_head *head)
+{
+	if (!list_empty(list)) {
+		__list_splice(list, head, head->next);
+		INIT_LIST_HEAD(list);
+	}
+}
+
+/**
+ * list_splice_tail_init - join two lists and reinitialise the emptied list
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * Each of the lists is a queue.
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_tail_init(struct list_head *list,
+					 struct list_head *head)
+{
+	if (!list_empty(list)) {
+		__list_splice(list, head->prev, head);
+		INIT_LIST_HEAD(list);
+	}
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:	the &struct list_head pointer.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+	container_of(ptr, type, member)
+
+/**
+ * list_for_each	-	iterate over a list
+ * @pos:	the &struct list_head to use as a loop counter.
+ * @head:	the head for your list.
+ */
+#define list_for_each(pos, head) \
+	for (pos = (head)->next; pos != (head); \
+		pos = pos->next)
+
+/**
+ * __list_for_each	-	iterate over a list
+ * @pos:	the &struct list_head to use as a loop counter.
+ * @head:	the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+	for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev	-	iterate over a list backwards
+ * @pos:	the &struct list_head to use as a loop counter.
+ * @head:	the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+	for (pos = (head)->prev; pos != (head); pos = pos->prev)
+
+/**
+ * list_for_each_safe	-	iterate over a list safe against removal of list entry
+ * @pos:	the &struct list_head to use as a loop counter.
+ * @n:		another &struct list_head to use as temporary storage
+ * @head:	the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+	for (pos = (head)->next, n = pos->next; pos != (head); \
+		pos = n, n = pos->next)
+
+/**
+ * list_for_each_entry	-	iterate over list of given type
+ * @pos:	the type * to use as a loop counter.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member)				\
+	for (pos = list_entry((head)->next, typeof(*pos), member);	\
+	     &pos->member != (head);					\
+	     pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos:	the type * to use as a loop counter.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member)			\
+	for (pos = list_entry((head)->prev, typeof(*pos), member);	\
+	     &pos->member != (head);					\
+	     pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos:	the type * to use as a loop counter.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member)			\
+	for (pos = list_entry((head)->next, typeof(*pos), member),	\
+		n = list_entry(pos->member.next, typeof(*pos), member);	\
+	     &pos->member != (head);					\
+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_reverse_safe - iterate backwards over list of given type safe against removal of list entry
+ * @pos:	the type * to use as a loop counter.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse_safe(pos, n, head, member)          \
+	for (pos = list_entry((head)->prev, typeof(*pos), member),      \
+		 n = list_entry(pos->member.prev, typeof(*pos), member);\
+	     &pos->member != (head);                                    \
+	     pos = n, n = list_entry(n->member.prev, typeof(*n), member))
+
+/**
+ * list_for_some_entry_safe - iterate list from the given begin node to the given end node safe against removal of list entry
+ * @pos:	the type * to use as a loop counter.
+ * @n:		another type * to use as temporary storage
+ * @from:	the begin node of the iteration.
+ * @to:		the end node of the iteration.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_some_entry_safe(pos, n, from, to, member)              \
+	for (pos = list_entry((from)->next, typeof(*pos), member),      \
+	     n = list_entry(pos->member.next, typeof(*pos), member);    \
+	     &pos->member != (to);                                      \
+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_some_entry_reverse_safe - iterate backwards list from the given begin node to the given end node safe against removal of list entry
+ * @pos:	the type * to use as a loop counter.
+ * @n:		another type * to use as temporary storage
+ * @from:	the begin node of the iteration.
+ * @to:		the end node of the iteration.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_some_entry_reverse_safe(pos, n, from, to, member)      \
+	for (pos = list_entry((from)->prev, typeof(*pos), member),      \
+	     n = list_entry(pos->member.prev, typeof(*pos), member);    \
+	     &pos->member != (to);                                      \
+	     pos = n, n = list_entry(n->member.prev, typeof(*n), member))
+
+#endif /* _LIST_H */
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:33:15 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:33:15 +0100
Subject: [PATCH 26/35] monitor: implement starting discovery controllers on
 startup
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-27-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

If the -U/--startup option is used, nvme monitor looks for exsiting
nvme controllers on startup, and runs a discovery on the associated
transport address (connection); i.e. tries to connect to a discovery
subsystem on the same address, retrieve the discovery log pages,
and (if --autoconnect is given) connect all listed controllers.

It depends on the --persistent option whether the discovery controllers
created in this process will be persistent after startup.

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 monitor.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/monitor.c b/monitor.c
index 5bd900b..e5d1982 100644
--- a/monitor.c
+++ b/monitor.c
@@ -43,6 +43,7 @@
 static struct monitor_config {
 	bool autoconnect;
 	bool skip_udev_on_exit;
+	bool start_ctrls;
 } mon_cfg;
 
 static struct udev *udev;
@@ -544,6 +545,20 @@ static void monitor_enable_udev_rules(void)
 		log(LOG_INFO, "removed %s\n", autoconnect_rules);
 }
 
+static int monitor_setup_discovery_ctrl(struct nvme_connection *co,
+					void *arg __attribute__((unused)))
+{
+	int rc;
+
+	if (co->discovery_instance >= 0)
+		return CD_CB_OK;
+
+	rc = monitor_discovery(co->transport, co->traddr, co->trsvcid,
+			       co->host_traddr, NULL);
+
+	return rc ? CD_CB_ERR : CD_CB_OK;
+}
+
 static int monitor_parse_opts(const char *desc, int argc, char **argv)
 {
 	bool quiet = false;
@@ -553,6 +568,7 @@ static int monitor_parse_opts(const char *desc, int argc, char **argv)
 
 	OPT_ARGS(opts) = {
 		OPT_FLAG("autoconnect",    'A', &mon_cfg.autoconnect, "automatically connect newly discovered controllers"),
+		OPT_FLAG("startup",        'U', &mon_cfg.start_ctrls, "start discovery controllers on startup"),
 		OPT_FLAG("persistent",     'p', &cfg.persistent,      "persistent discovery connections"),
 		OPT_FLAG("silent",         'S', &quiet,               "log level: silent"),
 		OPT_FLAG("verbose",        'v', &verbose,             "log level: verbose"),
@@ -604,6 +620,8 @@ int aen_monitor(const char *desc, int argc, char **argv)
 	ret = create_udev_monitor(&monitor);
 	if (ret == 0) {
 		conndb_init_from_sysfs();
+		if (mon_cfg.start_ctrls)
+			conndb_for_each(monitor_setup_discovery_ctrl, NULL);
 		ret = monitor_main_loop(monitor);
 		udev_monitor_unref(monitor);
 	}
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:33:11 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:33:11 +0100
Subject: [PATCH 22/35] conn-db: add simple connection registry
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-23-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

The monitor works best if it maintains a discovery controller connection
to every transport address that provides a discovery subsystem.

While controllers are easily tracked in sysfs, addresses ("connections"),
i.e. (transport, traddr, trsvid, host_traddr) tuples, are not. Create
a simple registry that tracks the state of "connections" and their
associated discovery controllers.

A detailed description of the API is provided in the header file conn-db.h.

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 Makefile  |   2 +-
 conn-db.c | 340 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 conn-db.h | 140 ++++++++++++++++++++++
 3 files changed, 481 insertions(+), 1 deletion(-)
 create mode 100644 conn-db.c
 create mode 100644 conn-db.h

diff --git a/Makefile b/Makefile
index 21c9a23..6ac5030 100644
--- a/Makefile
+++ b/Makefile
@@ -69,7 +69,7 @@ OBJS := nvme-print.o nvme-ioctl.o nvme-rpmb.o \
 	nvme-status.o nvme-filters.o nvme-topology.o
 
 ifeq ($(HAVE_LIBUDEV),0)
-	OBJS += monitor.o
+	OBJS += monitor.o conn-db.o
 endif
 
 UTIL_OBJS := util/argconfig.o util/suffix.o util/json.o util/parser.o
diff --git a/conn-db.c b/conn-db.c
new file mode 100644
index 0000000..99d88da
--- /dev/null
+++ b/conn-db.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2021 SUSE LLC
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This file implements a simple registry for NVMe connections, i.e.
+ * (transport type, host_traddr, traddr, trsvcid) tuples.
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <syslog.h>
+#include <time.h>
+
+#include "common.h"
+#include "list.h"
+#include "nvme.h"
+#include "fabrics.h"
+#include "conn-db.h"
+
+#define LOG_FUNCNAME 1
+#include "log.h"
+
+struct conn_int {
+	struct nvme_connection c;
+	struct list_head lst;
+};
+
+#define conn2internal(co) container_of(co, struct conn_int, c)
+
+static LIST_HEAD(connections);
+
+CLEANUP_FUNC(char)
+
+static const char * const _status_str[] = {
+	[CS_NEW] = "new",
+	[CS_DISC_RUNNING] = "discovery-running",
+	[CS_ONLINE] = "online",
+	[CS_FAILED] = "failed",
+};
+
+const char *conn_status_str(int status)
+{
+	return arg_str(_status_str, ARRAY_SIZE(_status_str), status);
+}
+
+#define _log_conn(lvl, msg, transport, traddr, trsvcid, host_traddr)	\
+	do {								\
+		const char *__trs = trsvcid;				\
+									\
+		log(lvl, "%s <%s>: %s ==> %s(%s)\n",			\
+		    msg, transport, host_traddr, traddr,		\
+		    __trs && *__trs ? __trs : "none");			\
+	} while (0)
+
+#define log_conn(lvl, msg, conn)					\
+	_log_conn(lvl, msg, (conn)->c.transport,			\
+		  (conn)->c.traddr, (conn)->c.trsvcid,			\
+		  (conn)->c.host_traddr)
+
+static void conn_free(struct conn_int *ci)
+{
+	if (!ci)
+		return;
+	if (ci->c.traddr)
+		free(ci->c.traddr);
+	if (ci->c.trsvcid)
+		free(ci->c.trsvcid);
+	if (ci->c.host_traddr)
+		free(ci->c.host_traddr);
+	free(ci);
+}
+
+static void conn_free_p(struct conn_int **ci)
+{
+	if (*ci) {
+		conn_free(*ci);
+		*ci = NULL;
+	}
+}
+
+static int conn_del(struct conn_int *ci)
+{
+	if (!ci)
+		return -ENOENT;
+	if (list_empty(&ci->lst))
+		return -EINVAL;
+	log_conn(LOG_INFO, "forgetting connection", ci);
+	list_del(&ci->lst);
+	conn_free(ci);
+	return 0;
+}
+
+bool conndb_matches(const char *transport, const char *traddr,
+		    const char *trsvcid, const char *host_traddr,
+		    const struct nvme_connection *co)
+{
+	if (!co)
+		return false;
+	if (!transport || strcmp(transport, co->transport))
+		return false;
+	if (!traddr || strncmp(traddr, co->traddr, NVMF_TRADDR_SIZE))
+		return false;
+	if ((!trsvcid && co->trsvcid) ||
+	    (trsvcid && *trsvcid && (!co->trsvcid ||
+			 strncmp(trsvcid, co->trsvcid, NVMF_TRSVCID_SIZE))))
+		return false;
+	if (!host_traddr || (strncmp(host_traddr, co->host_traddr,
+				     NVMF_TRADDR_SIZE)))
+		return false;
+	return true;
+}
+
+static struct conn_int *conn_find(const char *transport, const char *traddr,
+				  const char *trsvcid, const char *host_traddr)
+{
+	struct conn_int *ci;
+
+	if (!transport || !traddr || !host_traddr)
+		return NULL;
+	list_for_each_entry(ci, &connections, lst) {
+		if (conndb_matches(transport, traddr, trsvcid, host_traddr, &ci->c))
+			return ci;
+	}
+	return NULL;
+}
+
+static bool is_supported_transport(const char *transport)
+{
+
+	return !strcmp(transport, "fc") || !strcmp(transport, "rdma") ||
+	       !strcmp(transport, "tcp") || !strcmp(transport, "loop");
+}
+
+static int _conn_add(const char *transport, const char *traddr,
+		     const char *trsvcid, const char *host_traddr,
+		     struct conn_int **new_ci)
+{
+	struct conn_int *ci __attribute__((cleanup(conn_free_p))) = NULL;
+
+	if (!transport || !is_supported_transport(transport) || !traddr)
+		return -EINVAL;
+
+	if (!(ci = calloc(1, sizeof(*ci))) ||
+	    !(ci->c.traddr = strndup(traddr, NVMF_TRADDR_SIZE)) ||
+	    !(ci->c.host_traddr = strndup(host_traddr, NVMF_TRADDR_SIZE)) ||
+	    (trsvcid && *trsvcid &&
+	     !(ci->c.trsvcid = strndup(trsvcid, NVMF_TRSVCID_SIZE))))
+		return -ENOMEM;
+	memccpy(ci->c.transport, transport, '\0', sizeof(ci->c.transport));
+	ci->c.status = CS_NEW;
+	ci->c.discovery_instance = -1;
+	list_add(&ci->lst, &connections);
+	*new_ci = ci;
+	ci = NULL;
+	return 0;
+}
+
+static int conn_add(const char *transport, const char *traddr,
+		    const char *trsvcid, const char *host_traddr,
+		    struct conn_int **new_ci)
+{
+	struct conn_int *ci = conn_find(transport, traddr, trsvcid, host_traddr);
+	int rc;
+
+	if (ci) {
+		*new_ci = ci;
+		return -EEXIST;
+	}
+	rc = _conn_add(transport, traddr, trsvcid, host_traddr, new_ci);
+	if (!rc)
+		log_conn(LOG_DEBUG, "added connection", *new_ci);
+	else
+		_log_conn(LOG_ERR, "failed to add", transport, traddr,
+			  trsvcid, host_traddr);
+	return rc;
+}
+
+int conndb_add(const char *transport, const char *traddr,
+	       const char *trsvcid, const char *host_traddr,
+	       struct nvme_connection **new_conn)
+{
+	struct conn_int *ci = NULL;
+	int rc = conn_add(transport, traddr, trsvcid, host_traddr, &ci);
+
+	if (rc != 0 && rc != -EEXIST)
+		return rc;
+	if (new_conn)
+		*new_conn = &ci->c;
+	return rc;
+}
+
+struct nvme_connection *conndb_find(const char *transport, const char *traddr,
+				    const char *trsvcid, const char *host_traddr)
+{
+	struct conn_int *ci;
+
+	ci = conn_find(transport, traddr, trsvcid, host_traddr);
+	if (ci)
+		return &ci->c;
+	else
+		return NULL;
+}
+
+struct nvme_connection *conndb_find_by_pid(pid_t pid)
+{
+	struct conn_int *ci;
+
+	list_for_each_entry(ci, &connections, lst) {
+		if (ci->c.status == CS_DISC_RUNNING &&
+		    ci->c.discovery_task == pid)
+			return &ci->c;
+	}
+	return NULL;
+}
+
+struct nvme_connection *conndb_find_by_ctrl(const char *devname)
+{
+	struct conn_int *ci;
+	int instance;
+
+	instance = ctrl_instance(devname);
+	if (!instance)
+		return NULL;
+
+	list_for_each_entry(ci, &connections, lst) {
+		if (ci->c.discovery_instance == instance)
+			return &ci->c;
+	}
+	return NULL;
+}
+
+int conndb_delete(struct nvme_connection *co)
+{
+	if (!co)
+		return -ENOENT;
+	return conn_del(conn2internal(co));
+}
+
+void conndb_free(void)
+{
+	struct conn_int *ci, *next;
+
+	list_for_each_entry_safe(ci, next, &connections, lst)
+		conn_del(ci);
+}
+
+int conndb_init_from_sysfs(void)
+{
+	struct dirent **devices;
+	int i, n, ret = 0;
+	char syspath[PATH_MAX];
+
+	n = scandir(SYS_NVME, &devices, scan_ctrls_filter, alphasort);
+	if (n <= 0)
+		return n;
+
+	for (i = 0; i < n; i++) {
+		int len, rc;
+		struct conn_int *ci;
+		CLEANUP(char, transport) = NULL;
+		CLEANUP(char, address) = NULL;
+		CLEANUP(char, traddr) = NULL;
+		CLEANUP(char, trsvcid) = NULL;
+		CLEANUP(char, host_traddr) = NULL;
+		CLEANUP(char, subsysnqn) = NULL;
+
+		len = snprintf(syspath, sizeof(syspath), SYS_NVME "/%s",
+			       devices[i]->d_name);
+		if (len < 0 || len >= sizeof(syspath))
+			continue;
+
+		transport = nvme_get_ctrl_attr(syspath, "transport");
+		address = nvme_get_ctrl_attr(syspath, "address");
+		if (!transport || !address)
+			continue;
+		traddr = parse_conn_arg(address, ' ', "traddr");
+		trsvcid = parse_conn_arg(address, ' ', "trsvcid");
+		host_traddr = parse_conn_arg(address, ' ', "host_traddr");
+
+		rc = conn_add(transport, traddr, trsvcid, host_traddr, &ci);
+		if (rc != 0 && rc != -EEXIST)
+			continue;
+
+		if (rc == 0)
+			ret ++;
+		subsysnqn = nvme_get_ctrl_attr(syspath, "subsysnqn");
+		if (subsysnqn && !strcmp(subsysnqn, NVME_DISC_SUBSYS_NAME)) {
+			int instance = ctrl_instance(devices[i]->d_name);
+
+			if (instance >= 0) {
+				ci->c.discovery_instance = instance;
+				log(LOG_DEBUG, "found discovery controller %s\n",
+				    devices[i]->d_name);
+			}
+		}
+		free(devices[i]);
+	}
+	free(devices);
+	return ret;
+}
+
+int conndb_for_each(int (*callback)(struct nvme_connection *co, void *arg),
+		    void *arg)
+{
+	struct conn_int *ci, *next;
+	int ret = 0;
+
+	list_for_each_entry_safe(ci, next, &connections, lst) {
+		int rc = callback(&ci->c, arg);
+
+		if (rc & ~(CD_CB_ERR|CD_CB_DEL|CD_CB_BREAK)) {
+			log(LOG_ERR,
+			    "invalid return value 0x%x from callback\n", rc);
+			ret = -EINVAL;
+			continue;
+		}
+		if (rc & CD_CB_ERR) {
+			log(LOG_WARNING, "callback returned error\n");
+			if (!ret)
+				ret = errno ? -errno : -EIO;
+		}
+		if (rc & CD_CB_DEL)
+			conn_del(ci);
+		if (rc & CD_CB_BREAK)
+			break;
+	}
+	return ret;
+}
diff --git a/conn-db.h b/conn-db.h
new file mode 100644
index 0000000..c599c15
--- /dev/null
+++ b/conn-db.h
@@ -0,0 +1,140 @@
+#ifndef _CONN_DB_H
+#define _CONN_DB_H
+
+struct nvme_connection {
+	char transport[5];
+	char *traddr;
+	char *trsvcid;
+	char *host_traddr;
+
+	int status;
+	int discovery_pending:1;
+	int did_discovery:1;
+	int successful_discovery:1;
+	union {
+		pid_t discovery_task;
+		int discovery_result;
+	};
+	int discovery_instance;
+};
+
+/* connection status */
+enum {
+	CS_NEW = 0,
+	CS_DISC_RUNNING,
+	CS_ONLINE,
+	CS_FAILED,
+	__CS_LAST,
+};
+
+/**
+ * conn_status_str() - return string representation of connection status
+ */
+const char *conn_status_str(int status);
+
+/**
+ * conndb_add() - add a connection with given parameters
+ *
+ * @new_conn: if non-NULL and the function succeeds, will receive a pointer
+ *            to the either existing or newly created connection object.
+ *
+ * Looks up the given connection parameters in the db and adds a new connection
+ * unless found. All input parameters except trsvcid must be non-NULL.
+ *
+ * Return: 0 if controller was added, -EEXIST if controller existed in the db
+ *         (this is considered success), or other negative error code in
+ *         the error case.
+ *
+ */
+int conndb_add(const char *transport, const char *traddr,
+	       const char *trsvcid, const char *host_traddr,
+	       struct nvme_connection **new_conn);
+
+/**
+ * conndb_find() - lookup a connection with given parameters
+ *
+ * Return: NULL if not found, valid connection object otherwise.
+ */
+struct nvme_connection *conndb_find(const char *transport, const char *traddr,
+				    const char *trsvcid, const char *host_traddr);
+
+
+/**
+ * conndb_find_by_pid() - lookup connection by discovery task pid
+ *
+ * Return: valid connetion object if successful, NULL otherwise.
+ */
+struct nvme_connection *conndb_find_by_pid(pid_t pid);
+
+
+/**
+ * conndb_find_by_pid() - lookup connection from controller instance
+ *
+ * Return: valid connetion object if a connection was found that has
+ * the given device as discovery controller. NULL otherwise.
+ */
+struct nvme_connection *conndb_find_by_ctrl(const char *devname);
+
+enum {
+	CD_CB_OK    = 0,
+	CD_CB_ERR   = (1 << 0),
+	CD_CB_DEL   = (1 << 1),
+	CD_CB_BREAK = (1 << 2),
+};
+
+/**
+ *  conndb_for_each() - run a callback for each connection
+ *
+ * @callback: function to be called
+ * @arg:      user argument passed to callback
+ *
+ * The callback must return a bitmask created from the CD_CB_* enum
+ * values above. CD_CB_ERR signals an error condition in the callback.
+ * CD_CB_DEL causes the connection to be deleted after the callback
+ * returns. CD_CB_BREAK stops the iteration. Returning a value that
+ * is not an OR-ed from these values is an error.
+ *
+ * Return: 0 if all callbacks completed successfully.
+ *         A negative error code if some callback failed.
+ */
+int conndb_for_each(int (*callback)(struct nvme_connection *co, void *arg),
+		    void *arg);
+
+/**
+ * conndb_matches - check if connection matches given parameters
+ *
+ * The arguments @transport and @traddr must be non-null and non-empty.
+ * @trscvid and @host_traddr may be NULL, in which case they match
+ * connections that don't have these attributes set, either.
+ *
+ * Return: true iff the given connection matches the given attributes.
+ */
+bool conndb_matches(const char *transport, const char *traddr,
+		    const char *trsvcid, const char *host_traddr,
+		    const struct nvme_connection *co);
+
+/**
+ * conndb_delete() - remove a given nvme connection object
+ *
+ * Removes the object from the data base and frees it.
+ *
+ * Return: 0 if successful, negative error code otherwise
+ */
+int conndb_delete(struct nvme_connection *co);
+
+/**
+ * conndb-free() - free internal data structures
+ */
+void conndb_free(void);
+
+/**
+ * conndb_init_from_sysfs() - check existing NVMe connections
+ *
+ * Populates the connection db from existing contoller devices in sysfs.
+ *
+ * Return: (positive or zero) number of found connections on success.
+ *         Negative error code on failure.
+ */
+int conndb_init_from_sysfs(void);
+
+#endif
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:33:16 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:33:16 +0100
Subject: [PATCH 27/35] monitor: implement cleanup of created discovery
 controllers
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-28-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

If -A or -U was in use, try to clean up discovery controllers we set
up during runtime. Discovery connections that were already up when
the monitor started will not be teared down.

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 monitor.c | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/monitor.c b/monitor.c
index e5d1982..e3fee55 100644
--- a/monitor.c
+++ b/monitor.c
@@ -559,6 +559,39 @@ static int monitor_setup_discovery_ctrl(struct nvme_connection *co,
 	return rc ? CD_CB_ERR : CD_CB_OK;
 }
 
+static int monitor_remove_discovery_ctrl(struct nvme_connection *co,
+					void *arg __attribute__((unused)))
+{
+	char syspath[PATH_MAX];
+	int len;
+	CLEANUP(char, subsysnqn) = NULL;
+
+	if (co->discovery_instance == -1 || co->discovery_ctrl_existed)
+		return CD_CB_OK;
+
+	len = snprintf(syspath, sizeof(syspath), SYS_NVME "/nvme%d",
+		       co->discovery_instance);
+	if (len < 0 || len >= sizeof(syspath))
+		return CD_CB_ERR;
+
+	subsysnqn = nvme_get_ctrl_attr(syspath, "subsysnqn");
+	if (subsysnqn && !strcmp(subsysnqn, NVME_DISC_SUBSYS_NAME)) {
+		if (remove_ctrl(co->discovery_instance)) {
+			log(LOG_ERR,
+			    "failed to remove discovery controller /dev/nvme%d: %m\n",
+			    co->discovery_instance);
+			return CD_CB_ERR;
+		} else
+			log(LOG_INFO,
+			    "removed discovery controller /dev/nvme%d\n",
+			    co->discovery_instance);
+	} else
+		log(LOG_WARNING,
+		    "unexpected NQN %s on /dev/nvme%d, not removing controller\n",
+		    subsysnqn, co->discovery_instance);
+	return CD_CB_OK;
+}
+
 static int monitor_parse_opts(const char *desc, int argc, char **argv)
 {
 	bool quiet = false;
@@ -625,6 +658,8 @@ int aen_monitor(const char *desc, int argc, char **argv)
 		ret = monitor_main_loop(monitor);
 		udev_monitor_unref(monitor);
 	}
+	if (mon_cfg.autoconnect || mon_cfg.start_ctrls)
+		conndb_for_each(monitor_remove_discovery_ctrl, NULL);
 	conndb_free();
 	udev = udev_unref(udev);
 	if (mon_cfg.autoconnect && !mon_cfg.skip_udev_on_exit)
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:33:19 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:33:19 +0100
Subject: [PATCH 30/35] monitor: add connection property options from
 connect-all
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-31-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

This code is simply copied from fabrics_discover(). That's possible
because we simply access the fabric "cfg" variable directly.
These parameters are assumed to be constant over the runtime
of the monitor.

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 monitor.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/monitor.c b/monitor.c
index 37c9ace..ecf6706 100644
--- a/monitor.c
+++ b/monitor.c
@@ -669,6 +669,19 @@ static int monitor_parse_opts(const char *desc, int argc, char **argv)
 		OPT_FLAG("autoconnect",    'A', &mon_cfg.autoconnect, "automatically connect newly discovered controllers"),
 		OPT_FLAG("startup",        'U', &mon_cfg.start_ctrls, "start discovery controllers on startup"),
 		OPT_FLAG("persistent",     'p', &cfg.persistent,      "persistent discovery connections"),
+		OPT_LIST("hostnqn",        'q', &cfg.hostnqn,         "user-defined hostnqn (if default not used)"),
+		OPT_LIST("hostid",         'I', &cfg.hostid,          "user-defined hostid (if default not used)"),
+		OPT_INT("keep-alive-tmo",  'k', &cfg.keep_alive_tmo,  "keep alive timeout period in seconds"),
+		OPT_INT("reconnect-delay", 'c', &cfg.reconnect_delay, "reconnect timeout period in seconds"),
+		OPT_INT("ctrl-loss-tmo",   'l', &cfg.ctrl_loss_tmo,   "controller loss timeout period in seconds"),
+		OPT_INT("tos",             'T', &cfg.tos,             "type of service"),
+		OPT_FLAG("hdr_digest",     'g', &cfg.hdr_digest,      "enable transport protocol header digest (TCP transport)"),
+		OPT_FLAG("data_digest",    'G', &cfg.data_digest,     "enable transport protocol data digest (TCP transport)"),
+		OPT_INT("nr-io-queues",    'i', &cfg.nr_io_queues,    "number of io queues to use (default is core count)"),
+		OPT_INT("nr-write-queues", 'W', &cfg.nr_write_queues, "number of write queues to use (default 0)"),
+		OPT_INT("nr-poll-queues",  'P', &cfg.nr_poll_queues,  "number of poll queues to use (default 0)"),
+		OPT_INT("queue-size",      'Q', &cfg.queue_size,      "number of io queue elements to use (default 128)"),
+		OPT_FLAG("matching",       'm', &cfg.matching_only,   "connect only records matching the traddr"),
 		OPT_FLAG("silent",         'S', &quiet,               "log level: silent"),
 		OPT_FLAG("verbose",        'v', &verbose,             "log level: verbose"),
 		OPT_FLAG("debug",          'D', &debug,               "log level: debug"),
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:33:18 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:33:18 +0100
Subject: [PATCH 29/35] monitor: kill running discovery tasks on exit
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-30-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

Make sure discovery tasks terminate when the main process terminates.

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 monitor.c | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/monitor.c b/monitor.c
index e2c2568..37c9ace 100644
--- a/monitor.c
+++ b/monitor.c
@@ -630,6 +630,34 @@ static int monitor_remove_discovery_ctrl(struct nvme_connection *co,
 	return CD_CB_OK;
 }
 
+static int monitor_kill_discovery_task(struct nvme_connection *co,
+				       void *arg __attribute__((unused)))
+{
+	int wstatus;
+	pid_t pid, wpid = -1;
+
+	if (co->status != CS_DISC_RUNNING)
+		return CD_CB_OK;
+
+	pid = co->discovery_task;
+	co->status = CS_FAILED;
+	if (kill(co->discovery_task, SIGTERM) == -1) {
+		log(LOG_ERR, "failed to send SIGTERM to pid %ld: %m\n",
+		    (long)pid);
+		wpid = waitpid(pid, &wstatus, WNOHANG);
+	} else {
+		log(LOG_DEBUG, "sent SIGTERM to pid %ld, waiting\n", (long)pid);
+		wpid = waitpid(pid, &wstatus, 0);
+	}
+	if (wpid != pid) {
+		log(LOG_ERR, "failed to wait for %ld: %m\n", (long)pid);
+		return CD_CB_ERR;
+	} else {
+		log(LOG_DEBUG, "child %ld terminated\n", (long)pid);
+		return CD_CB_OK;
+	}
+}
+
 static int monitor_parse_opts(const char *desc, int argc, char **argv)
 {
 	bool quiet = false;
@@ -696,9 +724,12 @@ int aen_monitor(const char *desc, int argc, char **argv)
 		ret = monitor_main_loop(monitor);
 		udev_monitor_unref(monitor);
 	}
+
+	conndb_for_each(monitor_kill_discovery_task, NULL);
 	if (mon_cfg.autoconnect || mon_cfg.start_ctrls)
 		conndb_for_each(monitor_remove_discovery_ctrl, NULL);
 	conndb_free();
+
 	udev = udev_unref(udev);
 	if (mon_cfg.autoconnect && !mon_cfg.skip_udev_on_exit)
 		monitor_enable_udev_rules();
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:33:14 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:33:14 +0100
Subject: [PATCH 25/35] monitor: read existing connections on startup
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-26-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

Add discovery_ctrl_existed flag to the connection, to determine
whether a given (discovery) controller should be shut down on exit.

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 conn-db.c | 1 +
 conn-db.h | 1 +
 monitor.c | 2 ++
 3 files changed, 4 insertions(+)

diff --git a/conn-db.c b/conn-db.c
index 99d88da..07e4dde 100644
--- a/conn-db.c
+++ b/conn-db.c
@@ -301,6 +301,7 @@ int conndb_init_from_sysfs(void)
 
 			if (instance >= 0) {
 				ci->c.discovery_instance = instance;
+				ci->c.discovery_ctrl_existed = 1;
 				log(LOG_DEBUG, "found discovery controller %s\n",
 				    devices[i]->d_name);
 			}
diff --git a/conn-db.h b/conn-db.h
index c599c15..11c3502 100644
--- a/conn-db.h
+++ b/conn-db.h
@@ -11,6 +11,7 @@ struct nvme_connection {
 	int discovery_pending:1;
 	int did_discovery:1;
 	int successful_discovery:1;
+	int discovery_ctrl_existed:1;
 	union {
 		pid_t discovery_task;
 		int discovery_result;
diff --git a/monitor.c b/monitor.c
index ce772f3..5bd900b 100644
--- a/monitor.c
+++ b/monitor.c
@@ -603,9 +603,11 @@ int aen_monitor(const char *desc, int argc, char **argv)
 	}
 	ret = create_udev_monitor(&monitor);
 	if (ret == 0) {
+		conndb_init_from_sysfs();
 		ret = monitor_main_loop(monitor);
 		udev_monitor_unref(monitor);
 	}
+	conndb_free();
 	udev = udev_unref(udev);
 	if (mon_cfg.autoconnect && !mon_cfg.skip_udev_on_exit)
 		monitor_enable_udev_rules();
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:33:13 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:33:13 +0100
Subject: [PATCH 24/35] monitor: monitor_discovery(): try to reuse existing
 controllers
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-25-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

We need to pass cfg.device to do_discovery() if we want to re-use the
discovery controller device. Remember the instance number when
handling an AEN, and try to reuse this instance if the discovery
needs to be repeated.

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 monitor.c | 36 +++++++++++++++++++++++++++++++-----
 1 file changed, 31 insertions(+), 5 deletions(-)

diff --git a/monitor.c b/monitor.c
index b44ff7a..ce772f3 100644
--- a/monitor.c
+++ b/monitor.c
@@ -201,12 +201,14 @@ static int monitor_get_fc_uev_props(struct udev_device *ud,
 }
 
 static int monitor_discovery(const char *transport, const char *traddr,
-			     const char *trsvcid, const char *host_traddr)
+			     const char *trsvcid, const char *host_traddr,
+			     const char *devname)
 {
 	char argstr[BUF_SIZE];
 	pid_t pid;
 	int rc, db_rc;
 	struct nvme_connection *co = NULL;
+	char *device = NULL;
 
 	db_rc = conndb_add(transport, traddr, trsvcid, host_traddr, &co);
 	if (db_rc != 0 && db_rc != -EEXIST)
@@ -227,7 +229,15 @@ static int monitor_discovery(const char *transport, const char *traddr,
 		co->discovery_pending = 0;
 		co->status = CS_DISC_RUNNING;
 		co->discovery_task = pid;
+		if (devname) {
+			int instance = ctrl_instance(devname);
 
+			if (instance < 0) {
+				log(LOG_ERR, "unexpected devname: %s\n",
+				    devname);
+			} else
+				co->discovery_instance = instance;
+		}
 		return 0;
 	}
 
@@ -238,12 +248,26 @@ static int monitor_discovery(const char *transport, const char *traddr,
 	    trsvcid && *trsvcid ? trsvcid : "none",
 	    conn_status_str(co->status));
 
+	/*
+	 * Try to re-use existing controller. do_discovery() will check
+	 * if it matches the connection parameters.
+	 */
+	if (!devname && co->discovery_instance >= 0) {
+		if (asprintf(&device, "nvme%d", co->discovery_instance) == -1)
+			device = NULL;
+		else
+			devname = device;
+	}
+
+	if (devname)
+		log(LOG_INFO, "using discovery controller %s\n", devname);
 
 	cfg.nqn = NVME_DISC_SUBSYS_NAME;
 	cfg.transport = transport;
 	cfg.traddr = traddr;
 	cfg.trsvcid = trsvcid && *trsvcid ? trsvcid : NULL;
-	cfg.host_traddr = host_traddr;
+	cfg.host_traddr = host_traddr && *host_traddr ? host_traddr : NULL;
+	cfg.device = devname;
 	/* Without the following, the kernel returns EINVAL */
 	cfg.tos = -1;
 
@@ -251,6 +275,7 @@ static int monitor_discovery(const char *transport, const char *traddr,
 	log(LOG_DEBUG, "%s\n", argstr);
 	rc = do_discover(argstr, mon_cfg.autoconnect);
 
+	free(device);
 	exit(-rc);
 	/* not reached */
 	return rc;
@@ -269,7 +294,7 @@ static void monitor_handle_fc_uev(struct udev_device *ud)
 				     host_traddr, sizeof(host_traddr)))
 		return;
 
-	monitor_discovery("fc", traddr, NULL, host_traddr);
+	monitor_discovery("fc", traddr, NULL, host_traddr, NULL);
 }
 
 static int monitor_get_nvme_uev_props(struct udev_device *ud,
@@ -337,7 +362,8 @@ static void monitor_handle_nvme_uev(struct udev_device *ud)
 		return;
 
 	monitor_discovery(transport, traddr,
-			  strcmp(trsvcid, "none") ? trsvcid : NULL, host_traddr);
+			  strcmp(trsvcid, "none") ? trsvcid : NULL, host_traddr,
+			  udev_device_get_sysname(ud));
 }
 
 static void monitor_handle_udevice(struct udev_device *ud)
@@ -411,7 +437,7 @@ static void handle_sigchld(void)
 		if (co->discovery_pending) {
 			log(LOG_NOTICE, "new discovery pending - restarting\n");
 			monitor_discovery(co->transport, co->traddr,
-					  co->trsvcid, co->host_traddr);
+					  co->trsvcid, co->host_traddr, NULL);
 		}
 	};
 }
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:33:24 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:33:24 +0100
Subject: [PATCH 35/35] monitor: add option --keep/-K
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-36-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

With this option, "nvme monitor" will keep created discovery controllers
running even after it exits. If running in the initrd, this is will be
done automatically. That has the advantage that the new monitor instance
that will be started automatically after switching root can simply take
over the already created discovery controllers.

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 Documentation/nvme-monitor.1    | 28 +++++++++++++++++++++-------
 Documentation/nvme-monitor.html | 30 ++++++++++++++++++++++++------
 Documentation/nvme-monitor.txt  |  1 +
 monitor.c                       | 15 ++++++++++++++-
 4 files changed, 60 insertions(+), 14 deletions(-)

diff --git a/Documentation/nvme-monitor.1 b/Documentation/nvme-monitor.1
index 1578e4c..36b015d 100644
--- a/Documentation/nvme-monitor.1
+++ b/Documentation/nvme-monitor.1
@@ -2,12 +2,12 @@
 .\"     Title: nvme-monitor
 .\"    Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 01/20/2021
+.\"      Date: 01/25/2021
 .\"    Manual: NVMe Manual
 .\"    Source: NVMe
 .\"  Language: English
 .\"
-.TH "NVME\-MONITOR" "1" "01/20/2021" "NVMe" "NVMe Manual"
+.TH "NVME\-MONITOR" "1" "01/25/2021" "NVMe" "NVMe Manual"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -33,9 +33,10 @@ nvme-monitor \- Monitor Discovery events and Discover and Connect automatically
 .sp
 .nf
 \fInvme discover\fR
-                [\-\-autoconnect            | \-A
-                [\-\-startup                | \-U
-                [\-\-persistent             | \-p
+                [\-\-autoconnect            | \-A]
+                [\-\-startup                | \-U]
+                [\-\-persistent             | \-p]
+                [\-\-keep                   | \-K]
                 [\-\-hostnqn=<hostnqn>      | \-q <hostnqn>]
                 [\-\-hostid=<hostid>        | \-I <hostid>]
                 [\-\-keep\-alive\-tmo=<#>     | \-k <#>]
@@ -118,9 +119,22 @@ option to make the Discovery Controllers persist after retrieving the Discovery
 This option has the same meaning as for
 \fInvme discover\fR; Discovery Controllers will remain after the Discovery Log Page has been retrieved\&. This is necessary for receiving AENs from the transport connection that the Discovery controller is associated with\&. Without this option, AENs can only be received and acted upon if the administrator manually creates persistent Discovery controller connections\&. When
 \fInvme monitor\fR
-terminates, it will attempt to take down all Discovery Controllers it has created (i\&.e\&. ones that didn\(cqt already exist when
+terminates and the, it will attempt to take down all Discovery Controllers it has created (i\&.e\&. ones that didn\(cqt already exist when
 \fInvme monitor\fR
-was started\&.
+was started (but see
+\fI\-\-keep\fR)\&.
+.RE
+.PP
+\-K, \-\-keep
+.RS 4
+Do not tear down created persistent discovery controllers when exiting\&. This option makes only sense together with
+\fI\-\-persistent\fR\&. When
+\fInvme monitor\fR
+detects that it is running in the initial RAM FS (initrd),
+\fI\-\-keep\fR
+is implicitly assumed, i\&.e\&. discovery connections are not stopped\&. This is because after switching from the initrd to the real root file system, another
+\fInvme monitor\fR
+instance will probably be started that can reuse the created controller instances\&.
 .RE
 .PP
 \-q <hostnqn>, \-\-hostnqn=<hostnqn>, \-I <hostid>, \-\-hostid=<hostid>, \-k <#>, \-\-keep\-alive\-tmo=<#>, \-c <#>, \-\-reconnect\-delay=<#>, \-l <#>, \-\-ctrl\-loss\-tmo=<#>, \-g, \-\-hdr\-digest, \-G, \-\-data\-digest, \-i <#>, \-\-nr\-io\-queues=<#>, \-W <#>, \-\-nr\-write\-queues=<#>, \-P <#>, \-\-nr\-poll\-queues=<#>, \-Q <#>, \-\-queue\-size=<#>, \-m, \-\-matching
diff --git a/Documentation/nvme-monitor.html b/Documentation/nvme-monitor.html
index c2b9a64..bd57a22 100644
--- a/Documentation/nvme-monitor.html
+++ b/Documentation/nvme-monitor.html
@@ -750,9 +750,10 @@ nvme-monitor(1) Manual Page
 <div class="sectionbody">
 <div class="verseblock">
 <pre class="content"><em>nvme discover</em>
-                [--autoconnect            | -A
-                [--startup                | -U
-                [--persistent             | -p
+                [--autoconnect            | -A]
+                [--startup                | -U]
+                [--persistent             | -p]
+                [--keep                   | -K]
                 [--hostnqn=&lt;hostnqn&gt;      | -q &lt;hostnqn&gt;]
                 [--hostid=&lt;hostid&gt;        | -I &lt;hostid&gt;]
                 [--keep-alive-tmo=&lt;#&gt;     | -k &lt;#&gt;]
@@ -863,9 +864,26 @@ commands for further background.</p></div>
         this option, AENs can only be received and acted upon if the
         administrator manually creates persistent Discovery controller
         connections.
-        When <em>nvme monitor</em> terminates, it will attempt to take down all
+        When <em>nvme monitor</em> terminates and the, it will attempt to take down all
         Discovery Controllers it has created (i.e. ones that didn&#8217;t already
-        exist when <em>nvme monitor</em> was started.
+        exist when <em>nvme monitor</em> was started (but see <em>--keep</em>).
+</p>
+</dd>
+<dt class="hdlist1">
+-K
+</dt>
+<dt class="hdlist1">
+--keep
+</dt>
+<dd>
+<p>
+        Do not tear down created persistent discovery controllers when
+        exiting. This option makes only sense together with <em>--persistent</em>.
+        When <em>nvme monitor</em> detects that it is running in the initial RAM FS
+        (initrd), <em>--keep</em> is implicitly assumed, i.e. discovery connections
+        are not stopped. This is because after switching from the initrd to
+        the real root file system, another <em>nvme monitor</em> instance will
+        probably be started that can reuse the created controller instances.
 </p>
 </dd>
 <dt class="hdlist1">
@@ -1042,7 +1060,7 @@ nvme-connect-all(1)</p></div>
 <div id="footer">
 <div id="footer-text">
 Last updated
- 2021-01-20 23:53:52 CET
+ 2021-01-25 22:35:29 CET
 </div>
 </div>
 </body>
diff --git a/Documentation/nvme-monitor.txt b/Documentation/nvme-monitor.txt
index 9232fab..517d036 100644
--- a/Documentation/nvme-monitor.txt
+++ b/Documentation/nvme-monitor.txt
@@ -12,6 +12,7 @@ SYNOPSIS
 		[--autoconnect            | -A]
 		[--startup                | -U]
 		[--persistent             | -p]
+		[--keep                   | -K]
 		[--hostnqn=<hostnqn>      | -q <hostnqn>]
 		[--hostid=<hostid>        | -I <hostid>]
 		[--keep-alive-tmo=<#>     | -k <#>]
diff --git a/monitor.c b/monitor.c
index ecf6706..40d1f29 100644
--- a/monitor.c
+++ b/monitor.c
@@ -44,6 +44,7 @@ static struct monitor_config {
 	bool autoconnect;
 	bool skip_udev_on_exit;
 	bool start_ctrls;
+	bool keep_ctrls;
 } mon_cfg;
 
 static struct udev *udev;
@@ -669,6 +670,7 @@ static int monitor_parse_opts(const char *desc, int argc, char **argv)
 		OPT_FLAG("autoconnect",    'A', &mon_cfg.autoconnect, "automatically connect newly discovered controllers"),
 		OPT_FLAG("startup",        'U', &mon_cfg.start_ctrls, "start discovery controllers on startup"),
 		OPT_FLAG("persistent",     'p', &cfg.persistent,      "persistent discovery connections"),
+		OPT_FLAG("keep",           'K', &mon_cfg.keep_ctrls,  "keep discovery controllers after exit"),
 		OPT_LIST("hostnqn",        'q', &cfg.hostnqn,         "user-defined hostnqn (if default not used)"),
 		OPT_LIST("hostid",         'I', &cfg.hostid,          "user-defined hostid (if default not used)"),
 		OPT_INT("keep-alive-tmo",  'k', &cfg.keep_alive_tmo,  "keep alive timeout period in seconds"),
@@ -716,6 +718,11 @@ static int monitor_parse_opts(const char *desc, int argc, char **argv)
 	return ret;
 }
 
+static bool running_in_initrd(void)
+{
+	return access("/etc/initrd-release", F_OK) >= 0;
+}
+
 int aen_monitor(const char *desc, int argc, char **argv)
 {
 	int ret;
@@ -724,11 +731,16 @@ int aen_monitor(const char *desc, int argc, char **argv)
 	ret = monitor_parse_opts(desc, argc, argv);
 	if (ret)
 		goto out;
+
 	ret = monitor_init_signals();
 	if (ret != 0) {
 		log(LOG_ERR, "monitor: failed to initialize signals: %m\n");
 		goto out;
 	}
+
+	if (running_in_initrd())
+		mon_cfg.keep_ctrls = true;
+
 	ret = create_udev_monitor(&monitor);
 	if (ret == 0) {
 		conndb_init_from_sysfs();
@@ -739,7 +751,8 @@ int aen_monitor(const char *desc, int argc, char **argv)
 	}
 
 	conndb_for_each(monitor_kill_discovery_task, NULL);
-	if (mon_cfg.autoconnect || mon_cfg.start_ctrls)
+	if ((mon_cfg.autoconnect || mon_cfg.start_ctrls) &&
+	    !mon_cfg.keep_ctrls)
 		conndb_for_each(monitor_remove_discovery_ctrl, NULL);
 	conndb_free();
 
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:33:23 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:33:23 +0100
Subject: [PATCH 34/35] nvme-monitor(1): add man page for nvme-monitor
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-35-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 Documentation/cmds-main.txt     |    4 +
 Documentation/nvme-monitor.1    |  204 ++++++
 Documentation/nvme-monitor.html | 1049 +++++++++++++++++++++++++++++++
 Documentation/nvme-monitor.txt  |  169 +++++
 4 files changed, 1426 insertions(+)
 create mode 100644 Documentation/nvme-monitor.1
 create mode 100644 Documentation/nvme-monitor.html
 create mode 100644 Documentation/nvme-monitor.txt

diff --git a/Documentation/cmds-main.txt b/Documentation/cmds-main.txt
index 46df03d..d058a54 100644
--- a/Documentation/cmds-main.txt
+++ b/Documentation/cmds-main.txt
@@ -168,3 +168,7 @@ linknvme:nvme-disconnect-all[1]::
 
 linknvme:nvme-get-property[1]::
 	Reads and shows NVMe-over-Fabrics controller property
+
+linknvme:nvme-monitor[1]::
+	Monitor Discovery events and Discover and Connect automatically
+
diff --git a/Documentation/nvme-monitor.1 b/Documentation/nvme-monitor.1
new file mode 100644
index 0000000..1578e4c
--- /dev/null
+++ b/Documentation/nvme-monitor.1
@@ -0,0 +1,204 @@
+'\" t
+.\"     Title: nvme-monitor
+.\"    Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 01/20/2021
+.\"    Manual: NVMe Manual
+.\"    Source: NVMe
+.\"  Language: English
+.\"
+.TH "NVME\-MONITOR" "1" "01/20/2021" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-monitor \- Monitor Discovery events and Discover and Connect automatically
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme discover\fR
+                [\-\-autoconnect            | \-A
+                [\-\-startup                | \-U
+                [\-\-persistent             | \-p
+                [\-\-hostnqn=<hostnqn>      | \-q <hostnqn>]
+                [\-\-hostid=<hostid>        | \-I <hostid>]
+                [\-\-keep\-alive\-tmo=<#>     | \-k <#>]
+                [\-\-reconnect\-delay=<#>    | \-c <#>]
+                [\-\-ctrl\-loss\-tmo=<#>      | \-l <#>]
+                [\-\-hdr\-digest             | \-g]
+                [\-\-data\-digest            | \-G]
+                [\-\-nr\-io\-queues=<#>       | \-i <#>]
+                [\-\-nr\-write\-queues=<#>    | \-W <#>]
+                [\-\-nr\-poll\-queues=<#>     | \-P <#>]
+                [\-\-queue\-size=<#>         | \-Q <#>]
+                [\-\-matching               | \-m]
+                [\-\-persistent             | \-p]
+                [\-\-silent                 | \-S]
+                [\-\-verbose                | \-v]
+                [\-\-debug                  | \-D]
+                [\-\-clockstamps            | \-C]
+.fi
+.SH "DESCRIPTION"
+.sp
+Listen to Discovery events (Asynchronous Event Notifications, AENs) on NVMe\-over\-Fabrics (NVMeoF) Discovery Controllers and for other events related to NVMeoF Discovery, and optionally connect to newly discovered controllers\&.
+.sp
+If no parameters are given, then \fInvme monitor\fR listens to Discovery\-related udev events (uevents)\&. If an event is received, it connects to the Discovery Controller and performs the equivalent of an \fInvme discover\fR on the associated transport address\&. If the \fI\-\-autoconnect\fR option is given, it performs the equivalent of an \fInvme connect\-all\fR instead\&. When run through a systemd service in \fI\-\-autoconnect\fR mode, the monitor can be used as an alternative to the udev\-rule based auto\-activation of NVMeoF connections\&.
+.sp
+Currently, the following event types are supported:
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+"Discovery Log Page Change" Asynchronous Event Notifications (AENs) delivered via persistent connections to NVMeoF discovery controllers connected to the discovery service (nqn\&.2014\-08\&.org\&.nvmexpress\&.discovery)\&. Note that without the
+\fI\-\-persistent\fR
+option,
+\fInvme monitor\fR
+will not create persistent Discovery controllers itself, but it will receive and act upon AENs sent from persistent Discovery Controllers which were created manually or by other programs\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+FC\-NVMe auto\-connect uevents sent when the FibreChannel transport discovers N_Ports offering NVMe services\&.
+.RE
+.sp
+See the documentation for the nvme\-connect\-all(1) and nvme\-discover(1) commands for further background\&.
+.SH "OPTIONS"
+.PP
+\-A, \-\-autoconnect
+.RS 4
+If this option is given,
+\fInvme monitor\fR
+will attempt to connect to newly discovered controllers\&. In order to avoid race conditions with
+\fInvme connect\-all\fR
+commands spawned by udev rules via systemd\(cqs
+nvmf\-connect@\&.service, an empty rule is created under
+/run/udev/rules\&.d/70\-nvmf\-autoconnect\&.rules, disabling the udev rules that start this service\&. The file will be deleted when
+\fInvme monitor\fR
+terminates\&.
+.RE
+.PP
+\-U, \-\-startup
+.RS 4
+Look for existing NVMe connections (i\&.e\&. transport addresses with at least one connected controller) during startup, start a discovery controller on every detected connection, retrieve the log page and (if
+\fI\-\-autoconnect\fR
+is also given) connect to all discovered controllers\&. Use the
+\fI\-\-persistent\fR
+option to make the Discovery Controllers persist after retrieving the Discovery Log page\&.
+.RE
+.PP
+\-p, \-\-persistent
+.RS 4
+This option has the same meaning as for
+\fInvme discover\fR; Discovery Controllers will remain after the Discovery Log Page has been retrieved\&. This is necessary for receiving AENs from the transport connection that the Discovery controller is associated with\&. Without this option, AENs can only be received and acted upon if the administrator manually creates persistent Discovery controller connections\&. When
+\fInvme monitor\fR
+terminates, it will attempt to take down all Discovery Controllers it has created (i\&.e\&. ones that didn\(cqt already exist when
+\fInvme monitor\fR
+was started\&.
+.RE
+.PP
+\-q <hostnqn>, \-\-hostnqn=<hostnqn>, \-I <hostid>, \-\-hostid=<hostid>, \-k <#>, \-\-keep\-alive\-tmo=<#>, \-c <#>, \-\-reconnect\-delay=<#>, \-l <#>, \-\-ctrl\-loss\-tmo=<#>, \-g, \-\-hdr\-digest, \-G, \-\-data\-digest, \-i <#>, \-\-nr\-io\-queues=<#>, \-W <#>, \-\-nr\-write\-queues=<#>, \-P <#>, \-\-nr\-poll\-queues=<#>, \-Q <#>, \-\-queue\-size=<#>, \-m, \-\-matching
+.RS 4
+These options have the same meaning as for
+\fInvme connect\-all\fR\&. See the man page nvme\-connect\-all(1) for details\&.
+.RE
+.PP
+\-p, \-\-persistent
+.RS 4
+Don\(cqt remove the discovery controller after retrieving the discovery log page\&.
+.RE
+.PP
+\-S, \-\-silent
+.RS 4
+Only print warnings and severe error messages\&. Do not log discoveries and newly created controllers\&.
+.RE
+.PP
+\-v, \-\-verbose
+.RS 4
+Log informational messages\&. This option overrides
+\fI\-\-silent\fR\&.
+.RE
+.PP
+\-D, \-\-debug
+.RS 4
+Log informational and debug messages\&. This option overrieds
+\fI\-\-silent\fR
+and
+\fI\-\-verbose\fR\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Listen to FC\-NVME events and AENs, creating persistent Discovery Controllers on the way, and automatically connect to all discovered controllers:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme discover \-\-autoconnect \-\-persistent
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Like the above, but print more log messages and try to set up Discovery Controllers on startup, and using a different host NQN:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme discover \-\-autoconnect \-\-persistent \-\-startup \-\-verbose \e
+\-\-hostqn=host1\-rogue\-nqn
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "SEE ALSO"
+.sp
+nvme\-discover(1) nvme\-connect\-all(1)
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-monitor.html b/Documentation/nvme-monitor.html
new file mode 100644
index 0000000..c2b9a64
--- /dev/null
+++ b/Documentation/nvme-monitor.html
@@ -0,0 +1,1049 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc" />
+<title>nvme-monitor(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+  font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+  font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+  margin: 1em 5% 1em 5%;
+}
+
+a {
+  color: blue;
+  text-decoration: underline;
+}
+a:visited {
+  color: fuchsia;
+}
+
+em {
+  font-style: italic;
+  color: navy;
+}
+
+strong {
+  font-weight: bold;
+  color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+  color: #527bbd;
+  margin-top: 1.2em;
+  margin-bottom: 0.5em;
+  line-height: 1.3;
+}
+
+h1, h2, h3 {
+  border-bottom: 2px solid silver;
+}
+h2 {
+  padding-top: 0.5em;
+}
+h3 {
+  float: left;
+}
+h3 + * {
+  clear: left;
+}
+h5 {
+  font-size: 1.0em;
+}
+
+div.sectionbody {
+  margin-left: 0;
+}
+
+hr {
+  border: 1px solid silver;
+}
+
+p {
+  margin-top: 0.5em;
+  margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+  margin-top: 0;
+}
+ul > li     { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+  font-family: "Courier New", Courier, monospace;
+  font-size: inherit;
+  color: navy;
+  padding: 0;
+  margin: 0;
+}
+pre {
+  white-space: pre-wrap;
+}
+
+#author {
+  color: #527bbd;
+  font-weight: bold;
+  font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+  font-size: small;
+  border-top: 2px solid silver;
+  padding-top: 0.5em;
+  margin-top: 4.0em;
+}
+#footer-text {
+  float: left;
+  padding-bottom: 0.5em;
+}
+#footer-badges {
+  float: right;
+  padding-bottom: 0.5em;
+}
+
+#preamble {
+  margin-top: 1.5em;
+  margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+  margin-top: 1.0em;
+  margin-bottom: 1.5em;
+}
+div.admonitionblock {
+  margin-top: 2.0em;
+  margin-bottom: 2.0em;
+  margin-right: 10%;
+  color: #606060;
+}
+
+div.content { /* Block element content. */
+  padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+  color: #527bbd;
+  font-weight: bold;
+  text-align: left;
+  margin-top: 1.0em;
+  margin-bottom: 0.5em;
+}
+div.title + * {
+  margin-top: 0;
+}
+
+td div.title:first-child {
+  margin-top: 0.0em;
+}
+div.content div.title:first-child {
+  margin-top: 0.0em;
+}
+div.content + div.title {
+  margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+  background: #ffffee;
+  border: 1px solid #dddddd;
+  border-left: 4px solid #f0f0f0;
+  padding: 0.5em;
+}
+
+div.listingblock > div.content {
+  border: 1px solid #dddddd;
+  border-left: 5px solid #f0f0f0;
+  background: #f8f8f8;
+  padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+  padding-left: 1.0em;
+  margin-left: 1.0em;
+  margin-right: 10%;
+  border-left: 5px solid #f0f0f0;
+  color: #888;
+}
+
+div.quoteblock > div.attribution {
+  padding-top: 0.5em;
+  text-align: right;
+}
+
+div.verseblock > pre.content {
+  font-family: inherit;
+  font-size: inherit;
+}
+div.verseblock > div.attribution {
+  padding-top: 0.75em;
+  text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+  text-align: left;
+}
+
+div.admonitionblock .icon {
+  vertical-align: top;
+  font-size: 1.1em;
+  font-weight: bold;
+  text-decoration: underline;
+  color: #527bbd;
+  padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+  padding-left: 0.5em;
+  border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+  border-left: 3px solid #dddddd;
+  padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+  margin-top: 0.8em;
+  margin-bottom: 0.8em;
+}
+dt {
+  margin-top: 0.5em;
+  margin-bottom: 0;
+  font-style: normal;
+  color: navy;
+}
+dd > *:first-child {
+  margin-top: 0.1em;
+}
+
+ul, ol {
+    list-style-position: outside;
+}
+ol.arabic {
+  list-style-type: decimal;
+}
+ol.loweralpha {
+  list-style-type: lower-alpha;
+}
+ol.upperalpha {
+  list-style-type: upper-alpha;
+}
+ol.lowerroman {
+  list-style-type: lower-roman;
+}
+ol.upperroman {
+  list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+  margin-top: 0.1em;
+  margin-bottom: 0.1em;
+}
+
+tfoot {
+  font-weight: bold;
+}
+td > div.verse {
+  white-space: pre;
+}
+
+div.hdlist {
+  margin-top: 0.8em;
+  margin-bottom: 0.8em;
+}
+div.hdlist tr {
+  padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+  font-weight: bold;
+}
+td.hdlist1 {
+  vertical-align: top;
+  font-style: normal;
+  padding-right: 0.8em;
+  color: navy;
+}
+td.hdlist2 {
+  vertical-align: top;
+}
+div.hdlist.compact tr {
+  margin: 0;
+  padding-bottom: 0;
+}
+
+.comment {
+  background: yellow;
+}
+
+.footnote, .footnoteref {
+  font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+  vertical-align: super;
+}
+
+#footnotes {
+  margin: 20px 0 20px 0;
+  padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+  margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+  border: none;
+  border-top: 1px solid silver;
+  height: 1px;
+  text-align: left;
+  margin-left: 0;
+  width: 20%;
+  min-width: 100px;
+}
+
+div.colist td {
+  padding-right: 0.5em;
+  padding-bottom: 0.3em;
+  vertical-align: top;
+}
+div.colist td img {
+  margin-top: 0.3em;
+}
+
+ at media print {
+  #footer-badges { display: none; }
+}
+
+#toc {
+  margin-bottom: 2.5em;
+}
+
+#toctitle {
+  color: #527bbd;
+  font-size: 1.1em;
+  font-weight: bold;
+  margin-top: 1.0em;
+  margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+  margin-top: 0;
+  margin-bottom: 0;
+}
+div.toclevel2 {
+  margin-left: 2em;
+  font-size: 0.9em;
+}
+div.toclevel3 {
+  margin-left: 4em;
+  font-size: 0.9em;
+}
+div.toclevel4 {
+  margin-left: 6em;
+  font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+  margin-top: 1.0em;
+  margin-bottom: 1.5em;
+}
+div.tableblock > table {
+  border: 3px solid #527bbd;
+}
+thead, p.table.header {
+  font-weight: bold;
+  color: #527bbd;
+}
+p.table {
+  margin-top: 0;
+}
+/* Because the table frame attribute is overridden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+  border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+  border-left-style: none;
+  border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+  border-top-style: none;
+  border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+  margin-top: 1.0em;
+  margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+  font-weight: bold;
+  color: #527bbd;
+}
+p.tableblock {
+  margin-top: 0;
+}
+table.tableblock {
+  border-width: 3px;
+  border-spacing: 0px;
+  border-style: solid;
+  border-color: #527bbd;
+  border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+  border-width: 1px;
+  padding: 4px;
+  border-style: solid;
+  border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+  border-left-style: hidden;
+  border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+  border-top-style: hidden;
+  border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+  border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+  text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+  text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+  text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+  vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+  vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+  vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+  padding-top: 0.5em;
+  padding-bottom: 0.5em;
+  border-top: 2px solid silver;
+  border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+  border-style: none;
+}
+body.manpage div.sectionbody {
+  margin-left: 3em;
+}
+
+ at media print {
+  body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = {  // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+  function getText(el) {
+    var text = "";
+    for (var i = el.firstChild; i != null; i = i.nextSibling) {
+      if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+        text += i.data;
+      else if (i.firstChild != null)
+        text += getText(i);
+    }
+    return text;
+  }
+
+  function TocEntry(el, text, toclevel) {
+    this.element = el;
+    this.text = text;
+    this.toclevel = toclevel;
+  }
+
+  function tocEntries(el, toclevels) {
+    var result = new Array;
+    var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+    // Function that scans the DOM tree for header elements (the DOM2
+    // nodeIterator API would be a better technique but not supported by all
+    // browsers).
+    var iterate = function (el) {
+      for (var i = el.firstChild; i != null; i = i.nextSibling) {
+        if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+          var mo = re.exec(i.tagName);
+          if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+            result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+          }
+          iterate(i);
+        }
+      }
+    }
+    iterate(el);
+    return result;
+  }
+
+  var toc = document.getElementById("toc");
+  if (!toc) {
+    return;
+  }
+
+  // Delete existing TOC entries in case we're reloading the TOC.
+  var tocEntriesToRemove = [];
+  var i;
+  for (i = 0; i < toc.childNodes.length; i++) {
+    var entry = toc.childNodes[i];
+    if (entry.nodeName.toLowerCase() == 'div'
+     && entry.getAttribute("class")
+     && entry.getAttribute("class").match(/^toclevel/))
+      tocEntriesToRemove.push(entry);
+  }
+  for (i = 0; i < tocEntriesToRemove.length; i++) {
+    toc.removeChild(tocEntriesToRemove[i]);
+  }
+
+  // Rebuild TOC entries.
+  var entries = tocEntries(document.getElementById("content"), toclevels);
+  for (var i = 0; i < entries.length; ++i) {
+    var entry = entries[i];
+    if (entry.element.id == "")
+      entry.element.id = "_toc_" + i;
+    var a = document.createElement("a");
+    a.href = "#" + entry.element.id;
+    a.appendChild(document.createTextNode(entry.text));
+    var div = document.createElement("div");
+    div.appendChild(a);
+    div.className = "toclevel" + entry.toclevel;
+    toc.appendChild(div);
+  }
+  if (entries.length == 0)
+    toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+  // Delete existing footnote entries in case we're reloading the footnodes.
+  var i;
+  var noteholder = document.getElementById("footnotes");
+  if (!noteholder) {
+    return;
+  }
+  var entriesToRemove = [];
+  for (i = 0; i < noteholder.childNodes.length; i++) {
+    var entry = noteholder.childNodes[i];
+    if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+      entriesToRemove.push(entry);
+  }
+  for (i = 0; i < entriesToRemove.length; i++) {
+    noteholder.removeChild(entriesToRemove[i]);
+  }
+
+  // Rebuild footnote entries.
+  var cont = document.getElementById("content");
+  var spans = cont.getElementsByTagName("span");
+  var refs = {};
+  var n = 0;
+  for (i=0; i<spans.length; i++) {
+    if (spans[i].className == "footnote") {
+      n++;
+      var note = spans[i].getAttribute("data-note");
+      if (!note) {
+        // Use [\s\S] in place of . so multi-line matches work.
+        // Because JavaScript has no s (dotall) regex flag.
+        note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+        spans[i].innerHTML =
+          "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+          "' title='View footnote' class='footnote'>" + n + "</a>]";
+        spans[i].setAttribute("data-note", note);
+      }
+      noteholder.innerHTML +=
+        "<div class='footnote' id='_footnote_" + n + "'>" +
+        "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+        n + "</a>. " + note + "</div>";
+      var id =spans[i].getAttribute("id");
+      if (id != null) refs["#"+id] = n;
+    }
+  }
+  if (n == 0)
+    noteholder.parentNode.removeChild(noteholder);
+  else {
+    // Process footnoterefs.
+    for (i=0; i<spans.length; i++) {
+      if (spans[i].className == "footnoteref") {
+        var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+        href = href.match(/#.*/)[0];  // Because IE return full URL.
+        n = refs[href];
+        spans[i].innerHTML =
+          "[<a href='#_footnote_" + n +
+          "' title='View footnote' class='footnote'>" + n + "</a>]";
+      }
+    }
+  }
+},
+
+install: function(toclevels) {
+  var timerId;
+
+  function reinstall() {
+    asciidoc.footnotes();
+    if (toclevels) {
+      asciidoc.toc(toclevels);
+    }
+  }
+
+  function reinstallAndRemoveTimer() {
+    clearInterval(timerId);
+    reinstall();
+  }
+
+  timerId = setInterval(reinstall, 500);
+  if (document.addEventListener)
+    document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+  else
+    window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-monitor(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-monitor -
+   Monitor Discovery events and Discover and Connect automatically
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme discover</em>
+                [--autoconnect            | -A
+                [--startup                | -U
+                [--persistent             | -p
+                [--hostnqn=&lt;hostnqn&gt;      | -q &lt;hostnqn&gt;]
+                [--hostid=&lt;hostid&gt;        | -I &lt;hostid&gt;]
+                [--keep-alive-tmo=&lt;#&gt;     | -k &lt;#&gt;]
+                [--reconnect-delay=&lt;#&gt;    | -c &lt;#&gt;]
+                [--ctrl-loss-tmo=&lt;#&gt;      | -l &lt;#&gt;]
+                [--hdr-digest             | -g]
+                [--data-digest            | -G]
+                [--nr-io-queues=&lt;#&gt;       | -i &lt;#&gt;]
+                [--nr-write-queues=&lt;#&gt;    | -W &lt;#&gt;]
+                [--nr-poll-queues=&lt;#&gt;     | -P &lt;#&gt;]
+                [--queue-size=&lt;#&gt;         | -Q &lt;#&gt;]
+                [--matching               | -m]
+                [--persistent             | -p]
+                [--silent                 | -S]
+                [--verbose                | -v]
+                [--debug                  | -D]
+                [--clockstamps            | -C]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Listen to Discovery events (Asynchronous Event Notifications, AENs) on
+NVMe-over-Fabrics (NVMeoF) Discovery Controllers and for other events related
+to NVMeoF Discovery, and optionally connect to newly discovered controllers.</p></div>
+<div class="paragraph"><p>If no parameters are given, then <em>nvme monitor</em> listens to Discovery-related
+udev events (uevents). If an event is received, it connects to the Discovery
+Controller and performs the equivalent of an <em>nvme discover</em> on the associated
+transport address. If the <em>--autoconnect</em> option is given, it performs the
+equivalent of an <em>nvme connect-all</em> instead. When run through a systemd
+service in <em>--autoconnect</em> mode, the monitor can be used as an alternative to
+the udev-rule based auto-activation of NVMeoF connections.</p></div>
+<div class="paragraph"><p>Currently, the following event types are supported:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+"Discovery Log Page Change" Asynchronous Event Notifications (AENs)
+  delivered via persistent connections to NVMeoF discovery controllers
+  connected to the discovery service (<code>nqn.2014-08.org.nvmexpress.discovery</code>).
+  Note that without the <em>--persistent</em> option, <em>nvme monitor</em> will not create
+  persistent Discovery controllers itself, but it will receive and act upon
+  AENs sent from persistent Discovery Controllers which were created manually
+  or by other programs.
+</p>
+</li>
+<li>
+<p>
+FC-NVMe auto-connect uevents sent when the FibreChannel transport discovers
+  N_Ports offering NVMe services.
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>See the documentation for the nvme-connect-all(1) and nvme-discover(1)
+commands for further background.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-A
+</dt>
+<dt class="hdlist1">
+--autoconnect
+</dt>
+<dd>
+<p>
+        If this option is given, <em>nvme monitor</em> will attempt to connect to
+        newly discovered controllers.
+        In order to avoid race conditions with <em>nvme connect-all</em> commands
+        spawned by udev rules via systemd&#8217;s <code>nvmf-connect at .service</code>, an empty
+        rule is created under <code>/run/udev/rules.d/70-nvmf-autoconnect.rules</code>,
+        disabling the udev rules that start this service. The file will be
+        deleted when <em>nvme monitor</em> terminates.
+</p>
+</dd>
+<dt class="hdlist1">
+-U
+</dt>
+<dt class="hdlist1">
+--startup
+</dt>
+<dd>
+<p>
+        Look for existing NVMe connections (i.e. transport addresses with at
+        least one connected controller) during startup, start a discovery
+        controller on every detected connection, retrieve the log page and (if
+        <em>--autoconnect</em> is also given) connect to all discovered controllers.
+        Use the <em>--persistent</em> option to make the Discovery Controllers
+        persist after retrieving the Discovery Log page.
+</p>
+</dd>
+<dt class="hdlist1">
+-p
+</dt>
+<dt class="hdlist1">
+--persistent
+</dt>
+<dd>
+<p>
+        This option has the same meaning as for <em>nvme discover</em>; Discovery
+        Controllers will remain after the Discovery Log Page has been
+        retrieved. This is necessary for receiving AENs from the transport
+        connection that the Discovery controller is associated with. Without
+        this option, AENs can only be received and acted upon if the
+        administrator manually creates persistent Discovery controller
+        connections.
+        When <em>nvme monitor</em> terminates, it will attempt to take down all
+        Discovery Controllers it has created (i.e. ones that didn&#8217;t already
+        exist when <em>nvme monitor</em> was started.
+</p>
+</dd>
+<dt class="hdlist1">
+-q &lt;hostnqn&gt;
+</dt>
+<dt class="hdlist1">
+--hostnqn=&lt;hostnqn&gt;
+</dt>
+<dt class="hdlist1">
+-I &lt;hostid&gt;
+</dt>
+<dt class="hdlist1">
+--hostid=&lt;hostid&gt;
+</dt>
+<dt class="hdlist1">
+-k &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--keep-alive-tmo=&lt;#&gt;
+</dt>
+<dt class="hdlist1">
+-c &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--reconnect-delay=&lt;#&gt;
+</dt>
+<dt class="hdlist1">
+-l &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--ctrl-loss-tmo=&lt;#&gt;
+</dt>
+<dt class="hdlist1">
+-g
+</dt>
+<dt class="hdlist1">
+--hdr-digest
+</dt>
+<dt class="hdlist1">
+-G
+</dt>
+<dt class="hdlist1">
+--data-digest
+</dt>
+<dt class="hdlist1">
+-i &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--nr-io-queues=&lt;#&gt;
+</dt>
+<dt class="hdlist1">
+-W &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--nr-write-queues=&lt;#&gt;
+</dt>
+<dt class="hdlist1">
+-P &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--nr-poll-queues=&lt;#&gt;
+</dt>
+<dt class="hdlist1">
+-Q &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--queue-size=&lt;#&gt;
+</dt>
+<dt class="hdlist1">
+-m
+</dt>
+<dt class="hdlist1">
+--matching
+</dt>
+<dd>
+<p>
+        These options have the same meaning as for <em>nvme connect-all</em>. See the
+        man page nvme-connect-all(1) for details.
+</p>
+</dd>
+<dt class="hdlist1">
+-p
+</dt>
+<dt class="hdlist1">
+--persistent
+</dt>
+<dd>
+<p>
+        Don&#8217;t remove the discovery controller after retrieving the discovery
+        log page.
+</p>
+</dd>
+<dt class="hdlist1">
+-S
+</dt>
+<dt class="hdlist1">
+--silent
+</dt>
+<dd>
+<p>
+        Only print warnings and severe error messages. Do not log discoveries
+        and newly created controllers.
+</p>
+</dd>
+<dt class="hdlist1">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+        Log informational messages. This option overrides <em>--silent</em>.
+</p>
+</dd>
+<dt class="hdlist1">
+-D
+</dt>
+<dt class="hdlist1">
+--debug
+</dt>
+<dd>
+<p>
+        Log informational and debug messages. This option overrieds <em>--silent</em>
+        and <em>--verbose</em>.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Listen to FC-NVME events and AENs, creating persistent Discovery Controllers
+on the way, and automatically connect to all discovered controllers:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme discover --autoconnect --persistent</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Like the above, but print more log messages and try to set up Discovery
+Controllers on startup, and using a different host NQN:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme discover --autoconnect --persistent --startup --verbose \
+--hostqn=host1-rogue-nqn</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_see_also">SEE ALSO</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>nvme-discover(1)
+nvme-connect-all(1)</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the nvme-user suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2021-01-20 23:53:52 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-monitor.txt b/Documentation/nvme-monitor.txt
new file mode 100644
index 0000000..9232fab
--- /dev/null
+++ b/Documentation/nvme-monitor.txt
@@ -0,0 +1,169 @@
+nvme-monitor(1)
+===============
+
+NAME
+----
+nvme-monitor - Monitor Discovery events and Discover and Connect automatically
+
+SYNOPSIS
+--------
+[verse]
+'nvme discover'
+		[--autoconnect            | -A]
+		[--startup                | -U]
+		[--persistent             | -p]
+		[--hostnqn=<hostnqn>      | -q <hostnqn>]
+		[--hostid=<hostid>        | -I <hostid>]
+		[--keep-alive-tmo=<#>     | -k <#>]
+		[--reconnect-delay=<#>    | -c <#>]
+		[--ctrl-loss-tmo=<#>      | -l <#>]
+		[--hdr-digest             | -g]
+		[--data-digest            | -G]
+		[--nr-io-queues=<#>       | -i <#>]
+		[--nr-write-queues=<#>    | -W <#>]
+		[--nr-poll-queues=<#>     | -P <#>]
+		[--queue-size=<#>         | -Q <#>]
+		[--matching               | -m]
+		[--persistent             | -p]
+		[--silent                 | -S]
+		[--verbose                | -v]
+		[--debug                  | -D]
+		[--clockstamps            | -C]
+
+DESCRIPTION
+-----------
+Listen to Discovery events (Asynchronous Event Notifications, AENs) on
+NVMe-over-Fabrics (NVMeoF) Discovery Controllers and for other events related
+to NVMeoF Discovery, and optionally connect to newly discovered controllers.
+
+If no parameters are given, then 'nvme monitor' listens to Discovery-related
+udev events (uevents). If an event is received, it connects to the Discovery
+Controller and performs the equivalent of an 'nvme discover' on the associated
+transport address. If the '--autoconnect' option is given, it performs the
+equivalent of an 'nvme connect-all' instead. When run through a systemd
+service in '--autoconnect' mode, the monitor can be used as an alternative to
+the udev-rule based auto-activation of NVMeoF connections.
+
+Currently, the following event types are supported:
+
+- "Discovery Log Page Change" Asynchronous Event Notifications (AENs)
+  delivered via persistent connections to NVMeoF discovery controllers
+  connected to the discovery service (`nqn.2014-08.org.nvmexpress.discovery`).
+  Note that without the '--persistent' option, 'nvme monitor' will not create
+  persistent Discovery controllers itself, but it will receive and act upon
+  AENs sent from persistent Discovery Controllers which were created manually
+  or by other programs.
+
+- FC-NVMe auto-connect uevents sent when the FibreChannel transport discovers
+  N_Ports offering NVMe services.
+
+See the documentation for the nvme-connect-all(1) and nvme-discover(1)
+commands for further background.
+
+OPTIONS
+-------
+
+-A::
+--autoconnect::
+	If this option is given, 'nvme monitor' will attempt to connect to
+	newly discovered controllers.
+	In order to avoid race conditions with 'nvme connect-all' commands
+	spawned by udev rules via systemd's `nvmf-connect at .service`, an empty
+	rule is created under `/run/udev/rules.d/70-nvmf-autoconnect.rules`,
+	disabling the udev rules that start this service. The file will be
+	deleted when 'nvme monitor' terminates.
+	
+-U::
+--startup::
+	Look for existing NVMe connections (i.e. transport addresses with at
+	least one connected controller) during startup, start a discovery
+	controller on every detected connection, retrieve the log page and (if
+	'--autoconnect' is also given) connect to all discovered controllers.
+	Use the '--persistent' option to make the Discovery Controllers
+	persist after retrieving the Discovery Log page.
+
+-p::
+--persistent::
+	This option has the same meaning as for 'nvme discover'; Discovery
+	Controllers will remain after the Discovery Log Page has been
+	retrieved. This is necessary for receiving AENs from the transport
+	connection that the Discovery controller is associated with. Without
+	this option, AENs can only be received and acted upon if the
+	administrator manually creates persistent Discovery controller
+	connections.
+	When 'nvme monitor' terminates, it will attempt to take down all
+	Discovery Controllers it has created (i.e. ones that didn't already
+	exist when 'nvme monitor' was started.
+	
+-q <hostnqn>::
+--hostnqn=<hostnqn>::
+-I <hostid>::
+--hostid=<hostid>::
+-k <#>::
+--keep-alive-tmo=<#>::
+-c <#>::
+--reconnect-delay=<#>::
+-l <#>::
+--ctrl-loss-tmo=<#>::
+-g::
+--hdr-digest::
+-G::
+--data-digest::
+-i <#>::
+--nr-io-queues=<#>::
+-W <#>::
+--nr-write-queues=<#>::
+-P <#>::
+--nr-poll-queues=<#>::
+-Q <#>::
+--queue-size=<#>::
+-m::
+--matching::
+	These options have the same meaning as for 'nvme connect-all'. See the
+	man page nvme-connect-all(1) for details.
+
+-p::
+--persistent::
+	Don't remove the discovery controller after retrieving the discovery
+	log page.
+
+-S::
+--silent::
+	Only print warnings and severe error messages. Do not log discoveries
+	and newly created controllers.
+
+-v::
+--verbose::
+	Log informational messages. This option overrides '--silent'.
+
+-D::
+--debug::
+	Log informational and debug messages. This option overrieds '--silent'
+	and '--verbose'.
+
+
+EXAMPLES
+--------
+* Listen to FC-NVME events and AENs, creating persistent Discovery Controllers
+on the way, and automatically connect to all discovered controllers:
++
+------------
+# nvme discover --autoconnect --persistent
+------------
++
+* Like the above, but print more log messages and try to set up Discovery
+Controllers on startup, and using a different host NQN:
++
+-----------
+# nvme discover --autoconnect --persistent --startup --verbose \
+--hostqn=host1-rogue-nqn
+------------
+
+SEE ALSO
+--------
+nvme-discover(1)
+nvme-connect-all(1)
+
+NVME
+----
+Part of the nvme-user suite
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:33:21 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:33:21 +0100
Subject: [PATCH 32/35] nvmf-autoconnect: add unit file for nvme-monitor.service
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-33-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 nvmf-autoconnect/systemd/nvme-monitor.service | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
 create mode 100644 nvmf-autoconnect/systemd/nvme-monitor.service

diff --git a/nvmf-autoconnect/systemd/nvme-monitor.service b/nvmf-autoconnect/systemd/nvme-monitor.service
new file mode 100644
index 0000000..d85b133
--- /dev/null
+++ b/nvmf-autoconnect/systemd/nvme-monitor.service
@@ -0,0 +1,17 @@
+[Unit]
+Description=NVMe Event Monitor for Automatical Subsystem Connection
+Documentation=man:nvme-monitor(1)
+DefaultDependencies=false
+Requires=systemd-udevd-kernel.socket
+RequiresMountsFor=/sys
+Conflicts=shutdown.target
+After=systemd-udevd-kernel.socket
+Before=sysinit.target systemd-udev-trigger.service nvmefc-boot-connections.service
+
+[Service]
+Type=simple
+ExecStart=/usr/sbin/nvme monitor -A -p
+KillMode=mixed
+
+[Install]
+WantedBy=sysinit.target
-- 
2.29.2



From mwilck at suse.com  Tue Jan 26 15:33:22 2021
From: mwilck at suse.com (mwilck at suse.com)
Date: Tue, 26 Jan 2021 21:33:22 +0100
Subject: [PATCH 33/35] nvme-connect-all(1): fix documentation for --quiet/-S
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <20210126203324.23610-34-mwilck@suse.com>

From: Martin Wilck <mwilck at suse.com>

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 Documentation/nvme-connect-all.1    |  8 ++++----
 Documentation/nvme-connect-all.html | 10 +++++-----
 Documentation/nvme-connect-all.txt  |  4 ++--
 3 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/Documentation/nvme-connect-all.1 b/Documentation/nvme-connect-all.1
index 91d6896..a53a017 100644
--- a/Documentation/nvme-connect-all.1
+++ b/Documentation/nvme-connect-all.1
@@ -2,12 +2,12 @@
 .\"     Title: nvme-connect-all
 .\"    Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 10/20/2020
+.\"      Date: 01/20/2021
 .\"    Manual: NVMe Manual
 .\"    Source: NVMe
 .\"  Language: English
 .\"
-.TH "NVME\-CONNECT\-ALL" "1" "10/20/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-CONNECT\-ALL" "1" "01/20/2021" "NVMe" "NVMe Manual"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -51,7 +51,7 @@ nvme-connect-all \- Discover and Connect to Fabrics controllers\&.
                 [\-\-queue\-size=<#>         | \-Q <#>]
                 [\-\-matching               | \-m]
                 [\-\-persistent             | \-p]
-                [\-\-quiet                  | \-q]
+                [\-\-quiet                  | \-S]
 .fi
 .SH "DESCRIPTION"
 .sp
@@ -193,7 +193,7 @@ If a traddr was specified on the command line or in the configuration file, only
 Don\(cqt remove the discovery controller after retrieving the discovery log page\&.
 .RE
 .PP
-\-q, \-\-quiet
+\-S, \-\-quiet
 .RS 4
 Suppress error messages\&.
 .RE
diff --git a/Documentation/nvme-connect-all.html b/Documentation/nvme-connect-all.html
index beae013..f779c7b 100644
--- a/Documentation/nvme-connect-all.html
+++ b/Documentation/nvme-connect-all.html
@@ -4,7 +4,7 @@
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
 <head>
 <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
-<meta name="generator" content="AsciiDoc 8.6.10" />
+<meta name="generator" content="AsciiDoc" />
 <title>nvme-connect-all(1)</title>
 <style type="text/css">
 /* Shared CSS for AsciiDoc xhtml11 and html5 backends */
@@ -436,7 +436,7 @@ thead, p.table.header {
 p.table {
   margin-top: 0;
 }
-/* Because the table frame attribute is overriden by CSS in most browsers. */
+/* Because the table frame attribute is overridden by CSS in most browsers. */
 div.tableblock > table[frame="void"] {
   border-style: none;
 }
@@ -768,7 +768,7 @@ nvme-connect-all(1) Manual Page
                 [--queue-size=&lt;#&gt;         | -Q &lt;#&gt;]
                 [--matching               | -m]
                 [--persistent             | -p]
-                [--quiet                  | -q]</pre>
+                [--quiet                  | -S]</pre>
 <div class="attribution">
 </div></div>
 </div>
@@ -1048,7 +1048,7 @@ cellspacing="0" cellpadding="4">
 </p>
 </dd>
 <dt class="hdlist1">
--q
+-S
 </dt>
 <dt class="hdlist1">
 --quiet
@@ -1115,7 +1115,7 @@ nvme-connect(1)</p></div>
 <div id="footer">
 <div id="footer-text">
 Last updated
- 2020-10-20 16:47:21 PDT
+ 2021-01-20 23:40:57 CET
 </div>
 </div>
 </body>
diff --git a/Documentation/nvme-connect-all.txt b/Documentation/nvme-connect-all.txt
index 128f336..820dd6c 100644
--- a/Documentation/nvme-connect-all.txt
+++ b/Documentation/nvme-connect-all.txt
@@ -27,7 +27,7 @@ SYNOPSIS
 		[--queue-size=<#>         | -Q <#>]
 		[--matching               | -m]
 		[--persistent             | -p]
-		[--quiet                  | -q]
+		[--quiet                  | -S]
 
 DESCRIPTION
 -----------
@@ -154,7 +154,7 @@ OPTIONS
 	Don't remove the discovery controller after retrieving the discovery
 	log page.
 
--q::
+-S::
 --quiet::
 	Suppress error messages.
 
-- 
2.29.2



From Clay.Mayers at kioxia.com  Tue Jan 26 16:14:16 2021
From: Clay.Mayers at kioxia.com (Clay Mayers)
Date: Tue, 26 Jan 2021 21:14:16 +0000
Subject: [PATCH V2 0/2] nvme: Support for fused NVME_IOCTL_SUBMIT_IO
In-Reply-To: <BYAPR04MB49652EA8F4CF06D41C708E2386BC9@BYAPR04MB4965.namprd04.prod.outlook.com>
References: <20210105224939.1336-2-clay.mayers@kioxia.com>
 <20210125195844.1390581-1-clay.mayers@kioxia.com>
 <BYAPR04MB49650B6342C736B5268F833686BC9@BYAPR04MB4965.namprd04.prod.outlook.com>
 <b5c179e3eb904800931712d6b92cfbeb@kioxia.com>
 <BYAPR04MB49652EA8F4CF06D41C708E2386BC9@BYAPR04MB4965.namprd04.prod.outlook.com>
Message-ID: <70bbf9a1054e4d5e97078bbab201296f@kioxia.com>

> From: Chaitanya Kulkarni <Chaitanya.Kulkarni at wdc.com>
> Sent: Tuesday, January 26, 2021 11:01 AM
> 
> On 1/26/21 10:17 AM, Clay Mayers wrote:
> >>
> >> On 1/25/21 12:03, clay.mayers at kioxia.com wrote:
> >>> Local pci device fused support is also necessary for NVMeOF targets
> >>> to support fused operation.
> >> Please explain the use case and the application of the NVMeOF fuse
> >> command feature.
> > NVMeOF devices are used to create disaggregated storage systems where
> > compute and storage are connected over a fabric.  Fused compare/write
> > can be used to arbitrate shared access to NVMeOF devices w/o a central
> > authority.
> >
> > A specific example of how fused compare/write is used is the clustered
> > file system VMFS.  It uses the SCSI version of compare/write to manage
> > meta data on shared SAN systems.  File system meta data is updated
> > using locks stored on the storage media.  Those locks are grabbed
> > using fused compare/write operations as an atomic test & set.  VMFS
> > originally used device reserve, which is a courser gained locking
> > mechanism but it doesn't scale as well as an atomic test & set.
> If I understand correctly VMFS is out of tree filesystem is it ?
I seem to have misunderstood your request for a use-case.  As a patch series,
this is not about NVMeOF.  This is about pci support for the fused command.
NVMeOF is the use case for pci fused support.

But how strong of a use case is NVMeOF?  I offered clustered file systems
and the public example of VMWare's VMFS to illustrate the usefulness.
Here VMWare is the target and Linux is the host serving up storage over
NVMeOF.  That requires fused support the target/host and pci. With a
past company I worked for, we use the SPDK to get this functionality for
disaggregated storage.  That's right for some solutions but not all.

Our actual goal is to have something like direct device access without
something like the SPDK.  We think io uring is the correct solution.
Jens, just before his winter PTO, tweeted about adding ioctl support to
io uring.  We hope to extend that to support fused operations as well.
Exposing it through IOCTL makes the pci patch useful now.  The one
Example I have is for nvme-cli as requested on github.

https://github.com/linux-nvme/nvme-cli/issues/318

I thought this was better than folding an nvme change in with an io uring
patch series.  I'm trying to find the balance between a small isolated unit of
change and something compelling.
> Can you please explain the setup in detail ? what kind of interface file-system
> is using to issue the command ?
> Based on your description it looks like target is connected to the vmware
> based system and host is vmware based host and not the linux host which is
> present in this series.
No - the idea is to be standards based and use NVMeOF for target and host
data exchange.  In one example, the target would be running vSphere. The
host, as a Linux machine, would expose its attached devices with NVMeOF.
VSphere would expect fused command support from the Linux machine.
> Also what are other applications or is this the only one application?
The application is disaggregated storage on NVMeOF, both consuming it
and publishing it.  I don't have any specific set of applications to offer.



From kbusch at kernel.org  Tue Jan 26 19:59:33 2021
From: kbusch at kernel.org (Keith Busch)
Date: Tue, 26 Jan 2021 16:59:33 -0800
Subject: [PATCH] nvme-pci: add write-zeores SPCC quirk
In-Reply-To: <20210126051916.3271-1-chaitanya.kulkarni@wdc.com>
References: <20210126051916.3271-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210127005933.GA1816249@dhcp-10-100-145-180.wdc.com>

Looks fine,

Reviewed-by: Keith Busch <kbusch at kernel.org>


From yi.zhang at redhat.com  Tue Jan 26 22:35:59 2021
From: yi.zhang at redhat.com (Yi Zhang)
Date: Wed, 27 Jan 2021 11:35:59 +0800
Subject: [PATCH nvme-cli] Documentation: fix typo rtyep -> rtype
Message-ID: <20210127033559.20737-1-yi.zhang@redhat.com>

Signed-off-by: Yi Zhang <yi.zhang at redhat.com>
---
 Documentation/nvme-resv-acquire.1    | 2 +-
 Documentation/nvme-resv-acquire.html | 2 +-
 Documentation/nvme-resv-acquire.txt  | 2 +-
 Documentation/nvme-resv-release.1    | 2 +-
 Documentation/nvme-resv-release.html | 2 +-
 Documentation/nvme-resv-release.txt  | 2 +-
 6 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/Documentation/nvme-resv-acquire.1 b/Documentation/nvme-resv-acquire.1
index fef2398..1088479 100644
--- a/Documentation/nvme-resv-acquire.1
+++ b/Documentation/nvme-resv-acquire.1
@@ -59,7 +59,7 @@ Current Reservation Key: The field specifies the current reservation key associa
 Preempt Reservation Key: If the Reservation Acquire Action is set to 001b (i\&.e\&., Preempt) or 010b (i\&.e\&., Preempt and Abort), then this field specifies the reservation key to be unregistered from the namespace\&. For all other Reservation Acquire Action values, this field is reserved\&.
 .RE
 .PP
-\-t <rtype>, \-\-rtyep=<rtype>
+\-t <rtype>, \-\-rtype=<rtype>
 .RS 4
 Reservation Type: This field specifies the type of reservation to be created\&.
 .TS
diff --git a/Documentation/nvme-resv-acquire.html b/Documentation/nvme-resv-acquire.html
index 17b3d94..fabd8fd 100644
--- a/Documentation/nvme-resv-acquire.html
+++ b/Documentation/nvme-resv-acquire.html
@@ -815,7 +815,7 @@ reservation held on a namespace.</p></div>
 -t &lt;rtype&gt;
 </dt>
 <dt class="hdlist1">
---rtyep=&lt;rtype&gt;
+--rtype=&lt;rtype&gt;
 </dt>
 <dd>
 <p>
diff --git a/Documentation/nvme-resv-acquire.txt b/Documentation/nvme-resv-acquire.txt
index 41cbf8f..1b6e110 100644
--- a/Documentation/nvme-resv-acquire.txt
+++ b/Documentation/nvme-resv-acquire.txt
@@ -44,7 +44,7 @@ OPTIONS
 	this field is reserved.
 
 -t <rtype>::
---rtyep=<rtype>::
+--rtype=<rtype>::
 	Reservation Type: This field specifies the type of reservation
 	to be created.
 +
diff --git a/Documentation/nvme-resv-release.1 b/Documentation/nvme-resv-release.1
index 30fe9a9..5ade7f5 100644
--- a/Documentation/nvme-resv-release.1
+++ b/Documentation/nvme-resv-release.1
@@ -53,7 +53,7 @@ Override the nsid field\&. If using the admin character device, this parameter i
 Current Reservation Key: If the Reservation Register Action is 001b (i\&.e\&., Unregister Reservation Key) or 010b (i\&.e\&., Replace Reservation Key), then this field contains the current reservation key associated with the host\&. For all other Reservation Register Action values, this field is reserved\&. The controller ignores the value of this field when the Ignore Existing Key (IEKEY) bit is set to \(oq1\(cq\&.
 .RE
 .PP
-\-t <rtype>, \-\-rtyep=<rtype>
+\-t <rtype>, \-\-rtype=<rtype>
 .RS 4
 Reservation Type: This field specifies the type of reservation to be created\&.
 .TS
diff --git a/Documentation/nvme-resv-release.html b/Documentation/nvme-resv-release.html
index 884dc78..094c89a 100644
--- a/Documentation/nvme-resv-release.html
+++ b/Documentation/nvme-resv-release.html
@@ -802,7 +802,7 @@ held on a namespace.</p></div>
 -t &lt;rtype&gt;
 </dt>
 <dt class="hdlist1">
---rtyep=&lt;rtype&gt;
+--rtype=&lt;rtype&gt;
 </dt>
 <dd>
 <p>
diff --git a/Documentation/nvme-resv-release.txt b/Documentation/nvme-resv-release.txt
index a6a895e..6eb0b43 100644
--- a/Documentation/nvme-resv-release.txt
+++ b/Documentation/nvme-resv-release.txt
@@ -37,7 +37,7 @@ OPTIONS
 	bit is set to ?1?.
 
 -t <rtype>::
---rtyep=<rtype>::
+--rtype=<rtype>::
 	Reservation Type: This field specifies the type of reservation
 	to be created.
 +
-- 
2.21.0



From chaitanya.kulkarni at wdc.com  Wed Jan 27 00:37:38 2021
From: chaitanya.kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Tue, 26 Jan 2021 21:37:38 -0800
Subject: [PATCH] nvme-core: check bdev value for NULL
Message-ID: <20210127053738.4922-1-chaitanya.kulkarni@wdc.com>

The nvme-core sets the bdev to NULL when admin comamnd is issued from
IOCTL in the following path e.g. nvme list :-

block_ioctl()
 blkdev_ioctl()
  nvme_ioctl()
   nvme_user_cmd()
    nvme_submit_user_cmd()

The commit 309dca309fc3 ("block: store a block_device pointer in struct bio")
now uses bdev unconditionally in the macro bio_set_dev() and assumes
that bdev value is not NULL which results in the following crash in
since thats where bdev is actually accessed :-

void bio_associate_blkg_from_css(struct bio *bio,
				 struct cgroup_subsys_state *css)
{
	if (bio->bi_blkg)
		blkg_put(bio->bi_blkg);

	if (css && css->parent) {
		bio->bi_blkg = blkg_tryget_closest(bio, css);
	} else {
-------------->	blkg_get(bio->bi_bdev->bd_disk->queue->root_blkg);
		bio->bi_blkg = bio->bi_bdev->bd_disk->queue->root_blkg;
	}
}
EXPORT_SYMBOL_GPL(bio_associate_blkg_from_css);

<1>[  345.385947] BUG: kernel NULL pointer dereference, address: 0000000000000690
<1>[  345.387103] #PF: supervisor read access in kernel mode
<1>[  345.387894] #PF: error_code(0x0000) - not-present page
<6>[  345.388756] PGD 162a2b067 P4D 162a2b067 PUD 1633eb067 PMD 0
<4>[  345.389625] Oops: 0000 [#1] SMP NOPTI
<4>[  345.390206] CPU: 15 PID: 4100 Comm: nvme Tainted: G           OE     5.11.0-rc5blk+ #141
<4>[  345.391377] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.0-59-gc9ba52764
<4>[  345.393074] RIP: 0010:bio_associate_blkg_from_css.cold.47+0x58/0x21f

<4>[  345.396362] RSP: 0018:ffffc90000dbbce8 EFLAGS: 00010246
<4>[  345.397078] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000027
<4>[  345.398114] RDX: 0000000000000000 RSI: ffff888813be91f0 RDI: ffff888813be91f8
<4>[  345.399039] RBP: ffffc90000dbbd30 R08: 0000000000000001 R09: 0000000000000001
<4>[  345.399950] R10: 0000000064c66670 R11: 00000000ef955201 R12: ffff888812d32800
<4>[  345.401031] R13: 0000000000000000 R14: ffff888113e51540 R15: ffff888113e51540
<4>[  345.401976] FS:  00007f3747f1d780(0000) GS:ffff888813a00000(0000) knlGS:0000000000000000
<4>[  345.402997] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
<4>[  345.403737] CR2: 0000000000000690 CR3: 000000081a4bc000 CR4: 00000000003506e0
<4>[  345.404685] Call Trace:
<4>[  345.405031]  bio_associate_blkg+0x71/0x1c0
<4>[  345.405649]  nvme_submit_user_cmd+0x1aa/0x38e [nvme_core]
<4>[  345.406348]  nvme_user_cmd.isra.73.cold.98+0x54/0x92 [nvme_core]
<4>[  345.407117]  nvme_ioctl+0x226/0x260 [nvme_core]
<4>[  345.407707]  blkdev_ioctl+0x1c8/0x2b0
<4>[  345.408183]  block_ioctl+0x3f/0x50
<4>[  345.408627]  __x64_sys_ioctl+0x84/0xc0
<4>[  345.409117]  do_syscall_64+0x33/0x40
<4>[  345.409592]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
<4>[  345.410233] RIP: 0033:0x7f3747632107

<4>[  345.413125] RSP: 002b:00007ffe461b6648 EFLAGS: 00000206 ORIG_RAX: 0000000000000010
<4>[  345.414086] RAX: ffffffffffffffda RBX: 00000000007b7fd0 RCX: 00007f3747632107
<4>[  345.414998] RDX: 00007ffe461b6650 RSI: 00000000c0484e41 RDI: 0000000000000004
<4>[  345.415966] RBP: 0000000000000004 R08: 00000000007b7fe8 R09: 00000000007b9080
<4>[  345.416883] R10: 00007ffe461b62c0 R11: 0000000000000206 R12: 00000000007b7fd0
<4>[  345.417808] R13: 0000000000000000 R14: 0000000000000003 R15: 0000000000000000

Add a NULL check before we set the bdev for bio.

This issue is found on block/for-next tree.

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
---
 drivers/nvme/host/core.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index ba5df80881ea..1a3cdc6b1036 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -1133,7 +1133,8 @@ static int nvme_submit_user_cmd(struct request_queue *q,
 		if (ret)
 			goto out;
 		bio = req->bio;
-		bio_set_dev(bio, bdev);
+		if (bdev)
+			bio_set_dev(bio, bdev);
 		if (bdev && meta_buffer && meta_len) {
 			meta = nvme_add_user_metadata(bio, meta_buffer, meta_len,
 					meta_seed, write);
-- 
2.22.1



From hch at lst.de  Wed Jan 27 02:13:44 2021
From: hch at lst.de (Christoph Hellwig)
Date: Wed, 27 Jan 2021 08:13:44 +0100
Subject: [PATCH] nvme-core: check bdev value for NULL
In-Reply-To: <20210127053738.4922-1-chaitanya.kulkarni@wdc.com>
References: <20210127053738.4922-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210127071344.GA21223@lst.de>

Looks good:

Reviewed-by: Christoph Hellwig <hch at lst.de>

Jens, can you pick this up as it fixes an issue I introduced in
for-5.12/block?

On Tue, Jan 26, 2021 at 09:37:38PM -0800, Chaitanya Kulkarni wrote:
> The nvme-core sets the bdev to NULL when admin comamnd is issued from
> IOCTL in the following path e.g. nvme list :-
> 
> block_ioctl()
>  blkdev_ioctl()
>   nvme_ioctl()
>    nvme_user_cmd()
>     nvme_submit_user_cmd()
> 
> The commit 309dca309fc3 ("block: store a block_device pointer in struct bio")
> now uses bdev unconditionally in the macro bio_set_dev() and assumes
> that bdev value is not NULL which results in the following crash in
> since thats where bdev is actually accessed :-
> 
> void bio_associate_blkg_from_css(struct bio *bio,
> 				 struct cgroup_subsys_state *css)
> {
> 	if (bio->bi_blkg)
> 		blkg_put(bio->bi_blkg);
> 
> 	if (css && css->parent) {
> 		bio->bi_blkg = blkg_tryget_closest(bio, css);
> 	} else {
> -------------->	blkg_get(bio->bi_bdev->bd_disk->queue->root_blkg);
> 		bio->bi_blkg = bio->bi_bdev->bd_disk->queue->root_blkg;
> 	}
> }
> EXPORT_SYMBOL_GPL(bio_associate_blkg_from_css);
> 
> <1>[  345.385947] BUG: kernel NULL pointer dereference, address: 0000000000000690
> <1>[  345.387103] #PF: supervisor read access in kernel mode
> <1>[  345.387894] #PF: error_code(0x0000) - not-present page
> <6>[  345.388756] PGD 162a2b067 P4D 162a2b067 PUD 1633eb067 PMD 0
> <4>[  345.389625] Oops: 0000 [#1] SMP NOPTI
> <4>[  345.390206] CPU: 15 PID: 4100 Comm: nvme Tainted: G           OE     5.11.0-rc5blk+ #141
> <4>[  345.391377] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.0-59-gc9ba52764
> <4>[  345.393074] RIP: 0010:bio_associate_blkg_from_css.cold.47+0x58/0x21f
> 
> <4>[  345.396362] RSP: 0018:ffffc90000dbbce8 EFLAGS: 00010246
> <4>[  345.397078] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000027
> <4>[  345.398114] RDX: 0000000000000000 RSI: ffff888813be91f0 RDI: ffff888813be91f8
> <4>[  345.399039] RBP: ffffc90000dbbd30 R08: 0000000000000001 R09: 0000000000000001
> <4>[  345.399950] R10: 0000000064c66670 R11: 00000000ef955201 R12: ffff888812d32800
> <4>[  345.401031] R13: 0000000000000000 R14: ffff888113e51540 R15: ffff888113e51540
> <4>[  345.401976] FS:  00007f3747f1d780(0000) GS:ffff888813a00000(0000) knlGS:0000000000000000
> <4>[  345.402997] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> <4>[  345.403737] CR2: 0000000000000690 CR3: 000000081a4bc000 CR4: 00000000003506e0
> <4>[  345.404685] Call Trace:
> <4>[  345.405031]  bio_associate_blkg+0x71/0x1c0
> <4>[  345.405649]  nvme_submit_user_cmd+0x1aa/0x38e [nvme_core]
> <4>[  345.406348]  nvme_user_cmd.isra.73.cold.98+0x54/0x92 [nvme_core]
> <4>[  345.407117]  nvme_ioctl+0x226/0x260 [nvme_core]
> <4>[  345.407707]  blkdev_ioctl+0x1c8/0x2b0
> <4>[  345.408183]  block_ioctl+0x3f/0x50
> <4>[  345.408627]  __x64_sys_ioctl+0x84/0xc0
> <4>[  345.409117]  do_syscall_64+0x33/0x40
> <4>[  345.409592]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
> <4>[  345.410233] RIP: 0033:0x7f3747632107
> 
> <4>[  345.413125] RSP: 002b:00007ffe461b6648 EFLAGS: 00000206 ORIG_RAX: 0000000000000010
> <4>[  345.414086] RAX: ffffffffffffffda RBX: 00000000007b7fd0 RCX: 00007f3747632107
> <4>[  345.414998] RDX: 00007ffe461b6650 RSI: 00000000c0484e41 RDI: 0000000000000004
> <4>[  345.415966] RBP: 0000000000000004 R08: 00000000007b7fe8 R09: 00000000007b9080
> <4>[  345.416883] R10: 00007ffe461b62c0 R11: 0000000000000206 R12: 00000000007b7fd0
> <4>[  345.417808] R13: 0000000000000000 R14: 0000000000000003 R15: 0000000000000000
> 
> Add a NULL check before we set the bdev for bio.
> 
> This issue is found on block/for-next tree.
> 
> Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
> ---
>  drivers/nvme/host/core.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
> index ba5df80881ea..1a3cdc6b1036 100644
> --- a/drivers/nvme/host/core.c
> +++ b/drivers/nvme/host/core.c
> @@ -1133,7 +1133,8 @@ static int nvme_submit_user_cmd(struct request_queue *q,
>  		if (ret)
>  			goto out;
>  		bio = req->bio;
> -		bio_set_dev(bio, bdev);
> +		if (bdev)
> +			bio_set_dev(bio, bdev);
>  		if (bdev && meta_buffer && meta_len) {
>  			meta = nvme_add_user_metadata(bio, meta_buffer, meta_len,
>  					meta_seed, write);
> -- 
> 2.22.1
---end quoted text---


From hare at suse.de  Wed Jan 27 03:06:04 2021
From: hare at suse.de (Hannes Reinecke)
Date: Wed, 27 Jan 2021 09:06:04 +0100
Subject: [PATCH 1/2] nvme: add NVME_REQ_CANCELLED flag in nvme_cancel_request()
In-Reply-To: <20210127080605.146627-1-hare@suse.de>
References: <20210127080605.146627-1-hare@suse.de>
Message-ID: <20210127080605.146627-2-hare@suse.de>

NVME_REQ_CANCELLED is translated into -EINTR in nvme_submit_sync_cmd(),
so we should be setting this flags during nvme_cancel_request() to
ensure that the callers to nvme_submit_sync_cmd() will get the correct
error code when the controller is reset.

Signed-off-by: Hannes Reinecke <hare at suse.de>
---
 drivers/nvme/host/core.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index ce1b61519441..279d506ce794 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -367,6 +367,7 @@ bool nvme_cancel_request(struct request *req, void *data, bool reserved)
 		return true;
 
 	nvme_req(req)->status = NVME_SC_HOST_ABORTED_CMD;
+	nvme_req(req)->flags |= NVME_REQ_CANCELLED;
 	blk_mq_complete_request(req);
 	return true;
 }
-- 
2.29.2



From hare at suse.de  Wed Jan 27 03:06:05 2021
From: hare at suse.de (Hannes Reinecke)
Date: Wed, 27 Jan 2021 09:06:05 +0100
Subject: [PATCH 2/2] nvme: return -ETIMEDOUT in nvme_submit_sync_cmd()
In-Reply-To: <20210127080605.146627-1-hare@suse.de>
References: <20210127080605.146627-1-hare@suse.de>
Message-ID: <20210127080605.146627-3-hare@suse.de>

When a command times out we should be returning -ETIMEDOUT in
nvme_submit_sync_cmd(), and not requiring the caller to guess whether
a specific NVMe status should be interpreted as a timeout.

Signed-off-by: Hannes Reinecke <hare at suse.de>
---
 drivers/nvme/host/core.c | 2 ++
 drivers/nvme/host/nvme.h | 1 +
 drivers/nvme/host/rdma.c | 1 +
 drivers/nvme/host/tcp.c  | 1 +
 4 files changed, 5 insertions(+)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 279d506ce794..d7fea5a0aa1f 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -972,6 +972,8 @@ int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
 		*result = nvme_req(req)->result;
 	if (nvme_req(req)->flags & NVME_REQ_CANCELLED)
 		ret = -EINTR;
+	else if (nvme_req(req)->flags & NVME_REQ_TIMEOUT)
+		ret = -ETIMEDOUT;
 	else
 		ret = nvme_req(req)->status;
  out:
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 7e49f61f81df..0d3c16d9e493 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -167,6 +167,7 @@ struct nvme_request {
 enum {
 	NVME_REQ_CANCELLED		= (1 << 0),
 	NVME_REQ_USERCMD		= (1 << 1),
+	NVME_REQ_TIMEOUT		= (1 << 2),
 };
 
 static inline struct nvme_request *nvme_req(struct request *req)
diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index cf6c49d09c82..a4d5fbd50212 100644
--- a/drivers/nvme/host/rdma.c
+++ b/drivers/nvme/host/rdma.c
@@ -1977,6 +1977,7 @@ static void nvme_rdma_complete_timed_out(struct request *rq)
 	nvme_rdma_stop_queue(queue);
 	if (blk_mq_request_started(rq) && !blk_mq_request_completed(rq)) {
 		nvme_req(rq)->status = NVME_SC_HOST_ABORTED_CMD;
+		nvme_req(rq)->flags |= NVME_REQ_TIMEOUT;
 		blk_mq_complete_request(rq);
 	}
 }
diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 1ba659927442..21415cba1c69 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -2170,6 +2170,7 @@ static void nvme_tcp_complete_timed_out(struct request *rq)
 	nvme_tcp_stop_queue(ctrl, nvme_tcp_queue_id(req->queue));
 	if (blk_mq_request_started(rq) && !blk_mq_request_completed(rq)) {
 		nvme_req(rq)->status = NVME_SC_HOST_ABORTED_CMD;
+		nvme_req(rq)->flags |= NVME_REQ_TIMEOUT;
 		blk_mq_complete_request(rq);
 	}
 }
-- 
2.29.2



From hare at suse.de  Wed Jan 27 03:06:03 2021
From: hare at suse.de (Hannes Reinecke)
Date: Wed, 27 Jan 2021 09:06:03 +0100
Subject: [PATCH 0/2] Fixup return value for nvme_submit_sync_cmd()
Message-ID: <20210127080605.146627-1-hare@suse.de>

Hi all,

here are two small patches for fixing up the return value of nvme_submit_sync_cmd().
As Keith correctly noted, nvme_submit_sync_cmd() should be returning
an error if the command could not be performed; however, currently
only pci does that.
So the first patch fixes up nvme_cancel_request() to return an -EINTR
on any pending sync commands during reset.
And the second patch adds a new flag 'NVME_REQ_TIMEOUT' to indicate
that a command had been aborted due to a timeout, and translates that
back into -ETIMEDOUT as a return code for nvme_submit_sync_cmd().

As usual, comments and reviews are welcome.

Hannes Reinecke (2):
  nvme: add NVME_REQ_CANCELLED flag in nvme_cancel_request()
  nvme: return -ETIMEDOUT in nvme_submit_sync_cmd()

 drivers/nvme/host/core.c | 3 +++
 drivers/nvme/host/nvme.h | 1 +
 drivers/nvme/host/rdma.c | 1 +
 drivers/nvme/host/tcp.c  | 1 +
 4 files changed, 6 insertions(+)

-- 
2.29.2



From dwagner at suse.de  Wed Jan 27 04:14:50 2021
From: dwagner at suse.de (Daniel Wagner)
Date: Wed, 27 Jan 2021 10:14:50 +0100
Subject: [PATCH 1/2] nvme: add NVME_REQ_CANCELLED flag in
 nvme_cancel_request()
In-Reply-To: <20210127080605.146627-2-hare@suse.de>
References: <20210127080605.146627-1-hare@suse.de>
 <20210127080605.146627-2-hare@suse.de>
Message-ID: <20210127091450.r4n3bdvkqdfny4bf@beryllium.lan>

On Wed, Jan 27, 2021 at 09:06:04AM +0100, Hannes Reinecke wrote:
> NVME_REQ_CANCELLED is translated into -EINTR in nvme_submit_sync_cmd(),
> so we should be setting this flags during nvme_cancel_request() to
> ensure that the callers to nvme_submit_sync_cmd() will get the correct
> error code when the controller is reset.
> 
> Signed-off-by: Hannes Reinecke <hare at suse.de>

Reviewed-by: Daniel Wagner <dwagner at suse.de>


From dwagner at suse.de  Wed Jan 27 04:22:25 2021
From: dwagner at suse.de (Daniel Wagner)
Date: Wed, 27 Jan 2021 10:22:25 +0100
Subject: [PATCH 2/2] nvme: return -ETIMEDOUT in nvme_submit_sync_cmd()
In-Reply-To: <20210127080605.146627-3-hare@suse.de>
References: <20210127080605.146627-1-hare@suse.de>
 <20210127080605.146627-3-hare@suse.de>
Message-ID: <20210127092225.5b5n3bhp4edmhzic@beryllium.lan>

On Wed, Jan 27, 2021 at 09:06:05AM +0100, Hannes Reinecke wrote:
> When a command times out we should be returning -ETIMEDOUT in
> nvme_submit_sync_cmd(), and not requiring the caller to guess whether
> a specific NVMe status should be interpreted as a timeout.
> 
> Signed-off-by: Hannes Reinecke <hare at suse.de>
> ---
>  drivers/nvme/host/core.c | 2 ++
>  drivers/nvme/host/nvme.h | 1 +
>  drivers/nvme/host/rdma.c | 1 +
>  drivers/nvme/host/tcp.c  | 1 +

I wonder if we have to do something similar for FC. As far I understand
an abort command is issued and the drivers will return the original
request with FCPOP_STATE_ABORTED which then will be mapped to
NVME_SC_HOST_PATH_ERROR.

Can't say if this is good or bad, it's a just different.


From hare at suse.de  Wed Jan 27 05:04:35 2021
From: hare at suse.de (Hannes Reinecke)
Date: Wed, 27 Jan 2021 11:04:35 +0100
Subject: [PATCH 2/2] nvme: return -ETIMEDOUT in nvme_submit_sync_cmd()
In-Reply-To: <20210127092225.5b5n3bhp4edmhzic@beryllium.lan>
References: <20210127080605.146627-1-hare@suse.de>
 <20210127080605.146627-3-hare@suse.de>
 <20210127092225.5b5n3bhp4edmhzic@beryllium.lan>
Message-ID: <12b62ac4-f122-bc95-2615-b5f70ce54884@suse.de>

On 1/27/21 10:22 AM, Daniel Wagner wrote:
> On Wed, Jan 27, 2021 at 09:06:05AM +0100, Hannes Reinecke wrote:
>> When a command times out we should be returning -ETIMEDOUT in
>> nvme_submit_sync_cmd(), and not requiring the caller to guess whether
>> a specific NVMe status should be interpreted as a timeout.
>>
>> Signed-off-by: Hannes Reinecke <hare at suse.de>
>> ---
>>   drivers/nvme/host/core.c | 2 ++
>>   drivers/nvme/host/nvme.h | 1 +
>>   drivers/nvme/host/rdma.c | 1 +
>>   drivers/nvme/host/tcp.c  | 1 +
> 
> I wonder if we have to do something similar for FC. As far I understand
> an abort command is issued and the drivers will return the original
> request with FCPOP_STATE_ABORTED which then will be mapped to
> NVME_SC_HOST_PATH_ERROR.
> 
> Can't say if this is good or bad, it's a just different.
> 
Good point, and indeed you are correct.
Will be sending a v2 version.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare at suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 N?rnberg
HRB 36809 (AG N?rnberg), Gesch?ftsf?hrer: Felix Imend?rffer


From dwagner at suse.de  Wed Jan 27 05:30:33 2021
From: dwagner at suse.de (Daniel Wagner)
Date: Wed, 27 Jan 2021 11:30:33 +0100
Subject: [PATCH v2] nvme-multipath: Early exit if no path is available
Message-ID: <20210127103033.15318-1-dwagner@suse.de>

nvme_round_robin_path() should test if the return ns pointer is
valid. nvme_next_ns() will return a NULL pointer if there is no path
left.

Fixes: 75c10e732724 ("nvme-multipath: round-robin I/O policy")
Cc: Hannes Reinecke <hare at suse.de>
Signed-off-by: Daniel Wagner <dwagner at suse.de>
---
v2:
  - moved NULL test into the if conditional statement
  - added Fixes tag

 drivers/nvme/host/multipath.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
index 9ac762b28811..282b7a4ea9a9 100644
--- a/drivers/nvme/host/multipath.c
+++ b/drivers/nvme/host/multipath.c
@@ -221,7 +221,7 @@ static struct nvme_ns *nvme_round_robin_path(struct nvme_ns_head *head,
 	}
 
 	for (ns = nvme_next_ns(head, old);
-	     ns != old;
+	     ns && ns != old;
 	     ns = nvme_next_ns(head, ns)) {
 		if (nvme_path_is_disabled(ns))
 			continue;
-- 
2.29.2



From hare at suse.de  Wed Jan 27 05:33:21 2021
From: hare at suse.de (Hannes Reinecke)
Date: Wed, 27 Jan 2021 11:33:21 +0100
Subject: [PATCHv2 0/5][RESEND] Fixup return value for nvme_submit_sync_cmd()
Message-ID: <20210127103326.16191-1-hare@suse.de>

Hi all,

here are some small patches for fixing up the return value of nvme_submit_sync_cmd().
As Keith correctly noted, nvme_submit_sync_cmd() should be returning
an error if the command could not be performed; however, currently
only pci does that.
So we need to fix up nvme_cancel_request() to return an -EINTR
on any pending sync commands during reset.
And modify nvme-fc to return the same nvme status after timing out
or cancelling requests.
Plus, finally, adding a new flag 'NVME_REQ_TIMEOUT' to indicate
that a command had been aborted due to a timeout, and translates that
back into -ETIMEDOUT as a return code for nvme_submit_sync_cmd().

As usual, comments and reviews are welcome.

Changes to v1:
- Include reviews from Daniel
- Include changes for nvme-fc to return the same status as the
  other transports

Hannes Reinecke (5):
  nvme: add NVME_REQ_CANCELLED flag in nvme_cancel_request()
  nvme-fc: set NVME_REQ_CANCELLED in nvme_fc_terminate_exchange()
  nvme-fc: return NVME_SC_HOST_ABORTED_CMD when a command has been
    aborted
  nvme: return NVME_SC_ABORT_QUEUE for cancelled commands
  nvme: return -ETIMEDOUT in nvme_submit_sync_cmd()

 drivers/nvme/host/core.c |  5 ++++-
 drivers/nvme/host/fc.c   | 11 ++++++++---
 drivers/nvme/host/nvme.h |  1 +
 drivers/nvme/host/rdma.c |  1 +
 drivers/nvme/host/tcp.c  |  1 +
 5 files changed, 15 insertions(+), 4 deletions(-)

-- 
2.29.2



From hare at suse.de  Wed Jan 27 05:33:23 2021
From: hare at suse.de (Hannes Reinecke)
Date: Wed, 27 Jan 2021 11:33:23 +0100
Subject: [PATCH 2/5] nvme-fc: set NVME_REQ_CANCELLED in
 nvme_fc_terminate_exchange()
In-Reply-To: <20210127103326.16191-1-hare@suse.de>
References: <20210127103326.16191-1-hare@suse.de>
Message-ID: <20210127103326.16191-3-hare@suse.de>

nvme_fc_terminate_exchange() is being called when exchanges are
being deleted, and as such we should be setting the NVME_REQ_CANCELLED
flag to have identical behaviour on all transports.

Signed-off-by: Hannes Reinecke <hare at suse.de>
---
 drivers/nvme/host/fc.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c
index 20dadd86e981..ef12a619daec 100644
--- a/drivers/nvme/host/fc.c
+++ b/drivers/nvme/host/fc.c
@@ -2443,6 +2443,7 @@ nvme_fc_terminate_exchange(struct request *req, void *data, bool reserved)
 	struct nvme_fc_ctrl *ctrl = to_fc_ctrl(nctrl);
 	struct nvme_fc_fcp_op *op = blk_mq_rq_to_pdu(req);
 
+	op->nreq.flags |= NVME_REQ_CANCELLED;
 	__nvme_fc_abort_op(ctrl, op);
 	return true;
 }
-- 
2.29.2



From hare at suse.de  Wed Jan 27 05:33:22 2021
From: hare at suse.de (Hannes Reinecke)
Date: Wed, 27 Jan 2021 11:33:22 +0100
Subject: [PATCH 1/5] nvme: add NVME_REQ_CANCELLED flag in nvme_cancel_request()
In-Reply-To: <20210127103326.16191-1-hare@suse.de>
References: <20210127103326.16191-1-hare@suse.de>
Message-ID: <20210127103326.16191-2-hare@suse.de>

NVME_REQ_CANCELLED is translated into -EINTR in nvme_submit_sync_cmd(),
so we should be setting this flags during nvme_cancel_request() to
ensure that the callers to nvme_submit_sync_cmd() will get the correct
error code when the controller is reset.

Signed-off-by: Hannes Reinecke <hare at suse.de>
Reviewed-by: Daniel Wagner <dwagner at suse.de>
---
 drivers/nvme/host/core.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 2e09eed3d898..4a5059472625 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -365,6 +365,7 @@ bool nvme_cancel_request(struct request *req, void *data, bool reserved)
 		return true;
 
 	nvme_req(req)->status = NVME_SC_HOST_ABORTED_CMD;
+	nvme_req(req)->flags |= NVME_REQ_CANCELLED;
 	blk_mq_complete_request(req);
 	return true;
 }
-- 
2.29.2



From hare at suse.de  Wed Jan 27 05:33:25 2021
From: hare at suse.de (Hannes Reinecke)
Date: Wed, 27 Jan 2021 11:33:25 +0100
Subject: [PATCH 4/5] nvme: return NVME_SC_ABORT_QUEUE for cancelled commands
In-Reply-To: <20210127103326.16191-1-hare@suse.de>
References: <20210127103326.16191-1-hare@suse.de>
Message-ID: <20210127103326.16191-5-hare@suse.de>

A request will be cancelled when a queue is deleted, so we should
be returning a status of NVME_SC_ABORT_QUEUE.

Signed-off-by: Hannes Reinecke <hare at suse.de>
---
 drivers/nvme/host/core.c | 2 +-
 drivers/nvme/host/fc.c   | 9 ++++++---
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 4a5059472625..1f723b7e9efb 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -364,7 +364,7 @@ bool nvme_cancel_request(struct request *req, void *data, bool reserved)
 	if (blk_mq_request_completed(req))
 		return true;
 
-	nvme_req(req)->status = NVME_SC_HOST_ABORTED_CMD;
+	nvme_req(req)->status = NVME_SC_ABORT_QUEUE;
 	nvme_req(req)->flags |= NVME_REQ_CANCELLED;
 	blk_mq_complete_request(req);
 	return true;
diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c
index 97e3424c7b03..86395b66310d 100644
--- a/drivers/nvme/host/fc.c
+++ b/drivers/nvme/host/fc.c
@@ -1955,9 +1955,12 @@ nvme_fc_fcpio_done(struct nvmefc_fcp_req *req)
 	fc_dma_sync_single_for_cpu(ctrl->lport->dev, op->fcp_req.rspdma,
 				sizeof(op->rsp_iu), DMA_FROM_DEVICE);
 
-	if (opstate == FCPOP_STATE_ABORTED)
-		status = cpu_to_le16(NVME_SC_HOST_ABORTED_CMD << 1);
-	else if (freq->status) {
+	if (opstate == FCPOP_STATE_ABORTED) {
+		if (op->nreq.flags & NVME_REQ_CANCELLED)
+			status = cpu_to_le16(NVME_SC_ABORT_QUEUE << 1);
+		else
+			status = cpu_to_le16(NVME_SC_HOST_ABORTED_CMD << 1);
+	} else if (freq->status) {
 		status = cpu_to_le16(NVME_SC_HOST_PATH_ERROR << 1);
 		dev_info(ctrl->ctrl.device,
 			"NVME-FC{%d}: io failed due to lldd error %d\n",
-- 
2.29.2



From hare at suse.de  Wed Jan 27 05:33:24 2021
From: hare at suse.de (Hannes Reinecke)
Date: Wed, 27 Jan 2021 11:33:24 +0100
Subject: [PATCH 3/5] nvme-fc: return NVME_SC_HOST_ABORTED_CMD when a command
 has been aborted
In-Reply-To: <20210127103326.16191-1-hare@suse.de>
References: <20210127103326.16191-1-hare@suse.de>
Message-ID: <20210127103326.16191-4-hare@suse.de>

When a command has been aborted we should return NVME_SC_HOST_ABORTED_CMD
to be consistent with the other transports.

Signed-off-by: Hannes Reinecke <hare at suse.de>
---
 drivers/nvme/host/fc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c
index ef12a619daec..97e3424c7b03 100644
--- a/drivers/nvme/host/fc.c
+++ b/drivers/nvme/host/fc.c
@@ -1956,7 +1956,7 @@ nvme_fc_fcpio_done(struct nvmefc_fcp_req *req)
 				sizeof(op->rsp_iu), DMA_FROM_DEVICE);
 
 	if (opstate == FCPOP_STATE_ABORTED)
-		status = cpu_to_le16(NVME_SC_HOST_PATH_ERROR << 1);
+		status = cpu_to_le16(NVME_SC_HOST_ABORTED_CMD << 1);
 	else if (freq->status) {
 		status = cpu_to_le16(NVME_SC_HOST_PATH_ERROR << 1);
 		dev_info(ctrl->ctrl.device,
-- 
2.29.2



From hare at suse.de  Wed Jan 27 05:33:26 2021
From: hare at suse.de (Hannes Reinecke)
Date: Wed, 27 Jan 2021 11:33:26 +0100
Subject: [PATCH 5/5] nvme: return -ETIMEDOUT in nvme_submit_sync_cmd()
In-Reply-To: <20210127103326.16191-1-hare@suse.de>
References: <20210127103326.16191-1-hare@suse.de>
Message-ID: <20210127103326.16191-6-hare@suse.de>

When a command times out we should be returning -ETIMEDOUT in
nvme_submit_sync_cmd(), and not requiring the caller to guess whether
a specific NVMe status should be interpreted as a timeout.

Signed-off-by: Hannes Reinecke <hare at suse.de>
---
 drivers/nvme/host/core.c | 2 ++
 drivers/nvme/host/fc.c   | 1 +
 drivers/nvme/host/nvme.h | 1 +
 drivers/nvme/host/rdma.c | 1 +
 drivers/nvme/host/tcp.c  | 1 +
 5 files changed, 6 insertions(+)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 1f723b7e9efb..8376f65d52ca 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -969,6 +969,8 @@ int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
 		*result = nvme_req(req)->result;
 	if (nvme_req(req)->flags & NVME_REQ_CANCELLED)
 		ret = -EINTR;
+	else if (nvme_req(req)->flags & NVME_REQ_TIMEOUT)
+		ret = -ETIMEDOUT;
 	else
 		ret = nvme_req(req)->status;
  out:
diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c
index 86395b66310d..bcc086fcbe61 100644
--- a/drivers/nvme/host/fc.c
+++ b/drivers/nvme/host/fc.c
@@ -2551,6 +2551,7 @@ nvme_fc_timeout(struct request *rq, bool reserved)
 		"x%08x/x%08x\n",
 		ctrl->cnum, op->queue->qnum, sqe->common.opcode,
 		sqe->connect.fctype, sqe->common.cdw10, sqe->common.cdw11);
+	op->nreq.flags |= NVME_REQ_TIMEOUT;
 	if (__nvme_fc_abort_op(ctrl, op))
 		nvme_fc_error_recovery(ctrl, "io timeout abort failed");
 
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 88a6b97247f5..b0254692dc2a 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -167,6 +167,7 @@ struct nvme_request {
 enum {
 	NVME_REQ_CANCELLED		= (1 << 0),
 	NVME_REQ_USERCMD		= (1 << 1),
+	NVME_REQ_TIMEOUT		= (1 << 2),
 };
 
 static inline struct nvme_request *nvme_req(struct request *req)
diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index b7ce4f221d99..634ed5f5f778 100644
--- a/drivers/nvme/host/rdma.c
+++ b/drivers/nvme/host/rdma.c
@@ -1984,6 +1984,7 @@ static void nvme_rdma_complete_timed_out(struct request *rq)
 	nvme_rdma_stop_queue(queue);
 	if (blk_mq_request_started(rq) && !blk_mq_request_completed(rq)) {
 		nvme_req(rq)->status = NVME_SC_HOST_ABORTED_CMD;
+		nvme_req(rq)->flags |= NVME_REQ_TIMEOUT;
 		blk_mq_complete_request(rq);
 	}
 }
diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 4c13c7110dbe..eee9470bb1bd 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -2183,6 +2183,7 @@ static void nvme_tcp_complete_timed_out(struct request *rq)
 	nvme_tcp_stop_queue(ctrl, nvme_tcp_queue_id(req->queue));
 	if (blk_mq_request_started(rq) && !blk_mq_request_completed(rq)) {
 		nvme_req(rq)->status = NVME_SC_HOST_ABORTED_CMD;
+		nvme_req(rq)->flags |= NVME_REQ_TIMEOUT;
 		blk_mq_complete_request(rq);
 	}
 }
-- 
2.29.2



From hare at suse.de  Wed Jan 27 05:34:37 2021
From: hare at suse.de (Hannes Reinecke)
Date: Wed, 27 Jan 2021 11:34:37 +0100
Subject: [PATCH v2] nvme-multipath: Early exit if no path is available
In-Reply-To: <20210127103033.15318-1-dwagner@suse.de>
References: <20210127103033.15318-1-dwagner@suse.de>
Message-ID: <1563c0d6-cb24-0861-5a4a-a5aabfab7f9d@suse.de>

On 1/27/21 11:30 AM, Daniel Wagner wrote:
> nvme_round_robin_path() should test if the return ns pointer is
> valid. nvme_next_ns() will return a NULL pointer if there is no path
> left.
> 
> Fixes: 75c10e732724 ("nvme-multipath: round-robin I/O policy")
> Cc: Hannes Reinecke <hare at suse.de>
> Signed-off-by: Daniel Wagner <dwagner at suse.de>
> ---
> v2:
>    - moved NULL test into the if conditional statement
>    - added Fixes tag
> 
>   drivers/nvme/host/multipath.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
> index 9ac762b28811..282b7a4ea9a9 100644
> --- a/drivers/nvme/host/multipath.c
> +++ b/drivers/nvme/host/multipath.c
> @@ -221,7 +221,7 @@ static struct nvme_ns *nvme_round_robin_path(struct nvme_ns_head *head,
>   	}
>   
>   	for (ns = nvme_next_ns(head, old);
> -	     ns != old;
> +	     ns && ns != old;
>   	     ns = nvme_next_ns(head, ns)) {
>   		if (nvme_path_is_disabled(ns))
>   			continue;
> 
Reviewed-by: Hannes Reinecke <hare at suse.de>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare at suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 N?rnberg
HRB 36809 (AG N?rnberg), Gesch?ftsf?hrer: Felix Imend?rffer


From dwagner at suse.de  Wed Jan 27 05:59:49 2021
From: dwagner at suse.de (Daniel Wagner)
Date: Wed, 27 Jan 2021 11:59:49 +0100
Subject: [PATCH 2/5] nvme-fc: set NVME_REQ_CANCELLED in
 nvme_fc_terminate_exchange()
In-Reply-To: <20210127103326.16191-3-hare@suse.de>
References: <20210127103326.16191-1-hare@suse.de>
 <20210127103326.16191-3-hare@suse.de>
Message-ID: <20210127105949.yjwazlyif4eifvpt@beryllium.lan>

On Wed, Jan 27, 2021 at 11:33:23AM +0100, Hannes Reinecke wrote:
> nvme_fc_terminate_exchange() is being called when exchanges are
> being deleted, and as such we should be setting the NVME_REQ_CANCELLED
> flag to have identical behaviour on all transports.
> 
> Signed-off-by: Hannes Reinecke <hare at suse.de>

Reviewed-by: Daniel Wagner <dwagner at suse.de>


From dwagner at suse.de  Wed Jan 27 06:00:06 2021
From: dwagner at suse.de (Daniel Wagner)
Date: Wed, 27 Jan 2021 12:00:06 +0100
Subject: [PATCH 3/5] nvme-fc: return NVME_SC_HOST_ABORTED_CMD when a
 command has been aborted
In-Reply-To: <20210127103326.16191-4-hare@suse.de>
References: <20210127103326.16191-1-hare@suse.de>
 <20210127103326.16191-4-hare@suse.de>
Message-ID: <20210127110006.gx6j465hnz3j2p4v@beryllium.lan>

On Wed, Jan 27, 2021 at 11:33:24AM +0100, Hannes Reinecke wrote:
> When a command has been aborted we should return NVME_SC_HOST_ABORTED_CMD
> to be consistent with the other transports.
> 
> Signed-off-by: Hannes Reinecke <hare at suse.de>

Reviewed-by: Daniel Wagner <dwagner at suse.de>


From dwagner at suse.de  Wed Jan 27 06:00:19 2021
From: dwagner at suse.de (Daniel Wagner)
Date: Wed, 27 Jan 2021 12:00:19 +0100
Subject: [PATCH 5/5] nvme: return -ETIMEDOUT in nvme_submit_sync_cmd()
In-Reply-To: <20210127103326.16191-6-hare@suse.de>
References: <20210127103326.16191-1-hare@suse.de>
 <20210127103326.16191-6-hare@suse.de>
Message-ID: <20210127110019.fsi6ikq22fd6pssq@beryllium.lan>

On Wed, Jan 27, 2021 at 11:33:26AM +0100, Hannes Reinecke wrote:
> When a command times out we should be returning -ETIMEDOUT in
> nvme_submit_sync_cmd(), and not requiring the caller to guess whether
> a specific NVMe status should be interpreted as a timeout.
> 
> Signed-off-by: Hannes Reinecke <hare at suse.de>

Reviewed-by: Daniel Wagner <dwagner at suse.de>


From dwagner at suse.de  Wed Jan 27 06:01:11 2021
From: dwagner at suse.de (Daniel Wagner)
Date: Wed, 27 Jan 2021 12:01:11 +0100
Subject: [PATCH 4/5] nvme: return NVME_SC_ABORT_QUEUE for cancelled
 commands
In-Reply-To: <20210127103326.16191-5-hare@suse.de>
References: <20210127103326.16191-1-hare@suse.de>
 <20210127103326.16191-5-hare@suse.de>
Message-ID: <20210127110111.ojhxc4hbnuw2bq3v@beryllium.lan>

On Wed, Jan 27, 2021 at 11:30:31AM +0100, Hannes Reinecke wrote:
> A request will be cancelled when a queue is deleted, so we should
> be returning a status of NVME_SC_ABORT_QUEUE.

I think this patch should be spitted as it does two different
things.

> Signed-off-by: Hannes Reinecke <hare at suse.de>
> ---
>  drivers/nvme/host/core.c | 2 +-
>  drivers/nvme/host/fc.c   | 9 ++++++---
>  2 files changed, 7 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
> index 4a5059472625..1f723b7e9efb 100644
> --- a/drivers/nvme/host/core.c
> +++ b/drivers/nvme/host/core.c
> @@ -364,7 +364,7 @@ bool nvme_cancel_request(struct request *req, void *data, bool reserved)
>       if (blk_mq_request_completed(req))
>               return true;
>
> -     nvme_req(req)->status = NVME_SC_HOST_ABORTED_CMD;
> +     nvme_req(req)->status = NVME_SC_ABORT_QUEUE;
>       nvme_req(req)->flags |= NVME_REQ_CANCELLED;
>       blk_mq_complete_request(req);
>       return true;

The commit message describes this part of the change.

> diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c
> index 97e3424c7b03..86395b66310d 100644
> --- a/drivers/nvme/host/fc.c
> +++ b/drivers/nvme/host/fc.c
> @@ -1955,9 +1955,12 @@ nvme_fc_fcpio_done(struct nvmefc_fcp_req *req)
>       fc_dma_sync_single_for_cpu(ctrl->lport->dev, op->fcp_req.rspdma,
>                               sizeof(op->rsp_iu), DMA_FROM_DEVICE);
>
> -     if (opstate == FCPOP_STATE_ABORTED)
> -             status = cpu_to_le16(NVME_SC_HOST_ABORTED_CMD << 1);
> -     else if (freq->status) {
> +     if (opstate == FCPOP_STATE_ABORTED) {
> +             if (op->nreq.flags & NVME_REQ_CANCELLED)
> +                     status = cpu_to_le16(NVME_SC_ABORT_QUEUE << 1);
> +             else
> +                     status = cpu_to_le16(NVME_SC_HOST_ABORTED_CMD << 1);
> +     } else if (freq->status) {

IMO, this part is not explained in the commit message.


From colyli at suse.de  Wed Jan 27 08:12:07 2021
From: colyli at suse.de (Coly Li)
Date: Wed, 27 Jan 2021 21:12:07 +0800
Subject: [PATCH 2/3] bcache: use bio_set_dev to assign ->bi_bdev
In-Reply-To: <20210126143308.1960860-3-hch@lst.de>
References: <20210126143308.1960860-1-hch@lst.de>
 <20210126143308.1960860-3-hch@lst.de>
Message-ID: <19965f34-ed71-c5c4-cd6b-b4c7ac4d5e38@suse.de>

On 1/26/21 10:33 PM, Christoph Hellwig wrote:
> Always use the bio_set_dev helper to assign ->bi_bdev to make sure
> other state related to the device is uptodate.
> 
> Signed-off-by: Christoph Hellwig <hch at lst.de>

Acked-by: Coly Li <colyli at suse.de>


Coly Li

> ---
>  drivers/md/bcache/debug.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/md/bcache/debug.c b/drivers/md/bcache/debug.c
> index 058dd80144281e..63e809f38e3f51 100644
> --- a/drivers/md/bcache/debug.c
> +++ b/drivers/md/bcache/debug.c
> @@ -114,7 +114,7 @@ void bch_data_verify(struct cached_dev *dc, struct bio *bio)
>  	check = bio_kmalloc(GFP_NOIO, bio_segments(bio));
>  	if (!check)
>  		return;
> -	check->bi_bdev = bio->bi_bdev;
> +	bio_set_dev(check, bio->bi_bdev);
>  	check->bi_opf = REQ_OP_READ;
>  	check->bi_iter.bi_sector = bio->bi_iter.bi_sector;
>  	check->bi_iter.bi_size = bio->bi_iter.bi_size;
> 



From joshi.k at samsung.com  Wed Jan 27 10:00:25 2021
From: joshi.k at samsung.com (Kanchan Joshi)
Date: Wed, 27 Jan 2021 20:30:25 +0530
Subject: [RFC PATCH 0/4] Asynchronous passthrough ioctl
References: <CGME20210127150134epcas5p251fc1de3ff3581dd4c68b3fbe0b9dd91@epcas5p2.samsung.com>
Message-ID: <20210127150029.13766-1-joshi.k@samsung.com>

This RFC patchset adds asynchronous ioctl capability for NVMe devices.
Purpose of RFC is to get the feedback and optimize the path.

At the uppermost io-uring layer, a new opcode IORING_OP_IOCTL_PT is
presented to user-space applications. Like regular-ioctl, it takes
ioctl opcode and an optional argument (ioctl-specific input/output
parameter). Unlike regular-ioctl, it is made to skip the block-layer
and reach directly to the underlying driver (nvme in the case of this
patchset). This path between io-uring and nvme is via a newly
introduced block-device operation "async_ioctl". This operation
expects io-uring to supply a callback function which can be used to
report completion at later stage.

For a regular ioctl, NVMe driver submits the command to the device and
the submitter (task) is made to wait until completion arrives. For
async-ioctl, completion is decoupled from submission. Submitter goes
back to its business without waiting for nvme-completion. When
nvme-completion arrives, it informs io-uring via the registered
completion-handler. But some ioctls may require updating certain
ioctl-specific fields which can be accessed only in context of the
submitter task. For that reason, NVMe driver uses task-work infra for
that ioctl-specific update. Since task-work is not exported, it cannot
be referenced when nvme is compiled as a module. Therefore, one of the
patch exports task-work API.

Here goes example of usage (pseudo-code).
Actual nvme-cli source, modified to issue all ioctls via this opcode
is present at-
https://github.com/joshkan/nvme-cli/commit/a008a733f24ab5593e7874cfbc69ee04e88068c5

With regular ioctl-
int nvme_submit_passthru(int fd, unsigned long ioctl_cmd,
                         struct nvme_passthru_cmd *cmd)
{
	return ioctl(fd, ioctl_cmd, cmd);
}

With uring passthru ioctl-
int nvme_submit_passthru(int fd, unsigned long ioctl_cmd,
                         struct nvme_passthru_cmd *cmd)
{
	return uring_ioctl(fd, ioctl_cmd, cmd);
}
int uring_ioctl(int fd, unsinged long cmd, u64 arg)
{
	sqe = io_uring_get_sqe(ring);

	/* prepare sqe */
	sqe->fd = fd;
	sqe->opcode = IORING_OP_IOCTL_PT;
	sqe->ioctl_cmd = cmd;
	sqe->ioctl_arg = arg;

	/* submit sqe */
	io_uring_submit(ring);

	/* reap completion and obtain result */
	io_uring_wait_cqe(ring, &cqe);
	printf("ioctl result =%d\n", cqe->res)
}

Kanchan Joshi (4):
  block: introduce async ioctl operation
  kernel: export task_work_add
  nvme: add async ioctl support
  io_uring: add async passthrough ioctl support

 drivers/nvme/host/core.c      | 347 +++++++++++++++++++++++++++-------
 fs/io_uring.c                 |  77 ++++++++
 include/linux/blkdev.h        |  12 ++
 include/uapi/linux/io_uring.h |   7 +-
 kernel/task_work.c            |   2 +-
 5 files changed, 376 insertions(+), 69 deletions(-)

-- 
2.25.1



From joshi.k at samsung.com  Wed Jan 27 10:00:26 2021
From: joshi.k at samsung.com (Kanchan Joshi)
Date: Wed, 27 Jan 2021 20:30:26 +0530
Subject: [RFC PATCH 1/4] block: introduce async ioctl operation
In-Reply-To: <20210127150029.13766-1-joshi.k@samsung.com>
References: <20210127150029.13766-1-joshi.k@samsung.com>
 <CGME20210127150140epcas5p32832cc0c0db953db199eb9dd326f2d4c@epcas5p3.samsung.com>
Message-ID: <20210127150029.13766-2-joshi.k@samsung.com>

Add a new block-dev operation for async-ioctl.
Driver managing the block-dev can choose to implement it.

Signed-off-by: Kanchan Joshi <joshi.k at samsung.com>
---
 include/linux/blkdev.h | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index f94ee3089e01..c9f6cc26d675 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1848,6 +1848,16 @@ static inline void blk_ksm_unregister(struct request_queue *q) { }
 
 #endif /* CONFIG_BLK_INLINE_ENCRYPTION */
 
+struct pt_ioctl_ctx {
+	/* submitter task context */
+	struct task_struct *task;
+	/* callback supplied by upper layer */
+	void (*pt_complete)(struct pt_ioctl_ctx *ptioc, long ret);
+	/* driver-allocated data */
+	void *ioc_data;
+	/* to schedule task-work */
+	struct callback_head pt_work;
+};
 
 struct block_device_operations {
 	blk_qc_t (*submit_bio) (struct bio *bio);
@@ -1856,6 +1866,8 @@ struct block_device_operations {
 	int (*rw_page)(struct block_device *, sector_t, struct page *, unsigned int);
 	int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
 	int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
+	int (*async_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long,
+				struct pt_ioctl_ctx *);
 	unsigned int (*check_events) (struct gendisk *disk,
 				      unsigned int clearing);
 	void (*unlock_native_capacity) (struct gendisk *);
-- 
2.25.1



From joshi.k at samsung.com  Wed Jan 27 10:00:27 2021
From: joshi.k at samsung.com (Kanchan Joshi)
Date: Wed, 27 Jan 2021 20:30:27 +0530
Subject: [RFC PATCH 2/4] kernel: export task_work_add
In-Reply-To: <20210127150029.13766-1-joshi.k@samsung.com>
References: <20210127150029.13766-1-joshi.k@samsung.com>
 <CGME20210127150144epcas5p29ccb35d7e7170aba7947b5ee16fd2db0@epcas5p2.samsung.com>
Message-ID: <20210127150029.13766-3-joshi.k@samsung.com>

Task-work infra is required to introduce async-ioctl in nvme driver.
Without this being exported, NVMe needs to be built statically.

Signed-off-by: Kanchan Joshi <joshi.k at samsung.com>
---
 kernel/task_work.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/task_work.c b/kernel/task_work.c
index 9cde961875c0..3cf413c89639 100644
--- a/kernel/task_work.c
+++ b/kernel/task_work.c
@@ -57,7 +57,7 @@ int task_work_add(struct task_struct *task, struct callback_head *work,
 
 	return 0;
 }
-
+EXPORT_SYMBOL(task_work_add);
 /**
  * task_work_cancel - cancel a pending work added by task_work_add()
  * @task: the task which should execute the work
-- 
2.25.1



From joshi.k at samsung.com  Wed Jan 27 10:00:28 2021
From: joshi.k at samsung.com (Kanchan Joshi)
Date: Wed, 27 Jan 2021 20:30:28 +0530
Subject: [RFC PATCH 3/4] nvme: add async ioctl support
In-Reply-To: <20210127150029.13766-1-joshi.k@samsung.com>
References: <20210127150029.13766-1-joshi.k@samsung.com>
 <CGME20210127150149epcas5p4fa8edd47712f28ccdd9bac5139fc6e61@epcas5p4.samsung.com>
Message-ID: <20210127150029.13766-4-joshi.k@samsung.com>

Add async_ioctl handler that implements asynchronous handling of ioctl
operation. If requested ioctl opcode does not involve submitting a
command to device (e.g. NVME_IOCTL_ID), it is made to return instantly.
Otherwise, ioctl-completion is decoupled from submission, and
-EIOCBQUEUED is returned post submission. When completion arrives from
device, nvme calls the ioctl-completion handler supplied by upper-layer.
But there is execption to that. An ioctl completion may also require
updating certain ioctl-specific user buffers/fields which can be
accessed only in context of original submitter-task. For such ioctl,
nvme-completion schedules a task-work which first updates ioctl-specific
buffers/fields and after that invokes the ioctl-completion handler.

Signed-off-by: Kanchan Joshi <joshi.k at samsung.com>
Signed-off-by: Anuj Gupta <anuj20.g at samsung.com>
---
 drivers/nvme/host/core.c | 347 +++++++++++++++++++++++++++++++--------
 1 file changed, 280 insertions(+), 67 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 200bdd672c28..57f3040bae34 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -21,6 +21,7 @@
 #include <linux/nvme_ioctl.h>
 #include <linux/pm_qos.h>
 #include <asm/unaligned.h>
+#include <linux/task_work.h>
 
 #include "nvme.h"
 #include "fabrics.h"
@@ -1092,7 +1093,107 @@ static void nvme_passthru_end(struct nvme_ctrl *ctrl, u32 effects)
 	}
 }
 
-void nvme_execute_passthru_rq(struct request *rq)
+struct async_pt_desc {
+	struct bio *bio;
+	int status; /* command status */
+	u64 result; /* nvme cmd result */
+	void __user *res_ptr; /* can be null, 32bit addr or 64 bit addr */
+	void __user *meta_ptr;
+	void *meta; /* kernel-space resident buffer */
+	unsigned metalen; /* length of meta */
+	bool is_res64 : 1; /* res_ptr refers to 64bit of space */
+	bool is_write : 1;
+	bool is_taskwork : 1;
+};
+
+static int nvme_add_task_work(struct task_struct *tsk,
+			struct callback_head *twork,
+			task_work_func_t work_func)
+{
+	int ret;
+
+	get_task_struct(tsk);
+	init_task_work(twork, work_func);
+	ret = task_work_add(tsk, twork, TWA_SIGNAL);
+	if (!ret)
+		wake_up_process(tsk);
+	return ret;
+}
+
+static void async_pt_update_work(struct callback_head *cbh)
+{
+	struct pt_ioctl_ctx *ptioc;
+	struct async_pt_desc *ptd;
+	struct task_struct *tsk;
+	int ret;
+
+	ptioc = container_of(cbh, struct pt_ioctl_ctx, pt_work);
+	ptd = ptioc->ioc_data;
+	tsk = ptioc->task;
+
+	/* handle meta update */
+	if (ptd->meta) {
+		if (!ptd->status && !ptd->is_write)
+			if (copy_to_user(ptd->meta_ptr, ptd->meta, ptd->metalen))
+				ptd->status = -EFAULT;
+		kfree(ptd->meta);
+	}
+	/* handle result update */
+	if (ptd->res_ptr) {
+		if (!ptd->is_res64)
+			ret = put_user(ptd->result, (u32 __user *)ptd->res_ptr);
+		else
+			ret = put_user(ptd->result, (u64 __user *)ptd->res_ptr);
+		if (ret)
+			ptd->status = -EFAULT;
+	}
+
+	ptioc->pt_complete(ptioc, ptd->status);
+	put_task_struct(tsk);
+	kfree(ptd);
+}
+
+static void nvme_end_async_pt(struct request *req, blk_status_t err)
+{
+	struct pt_ioctl_ctx *ptioc;
+	struct async_pt_desc *ptd;
+	struct bio *bio;
+
+	ptioc = req->end_io_data;
+	ptd = ptioc->ioc_data;
+
+	if (nvme_req(req)->flags & NVME_REQ_CANCELLED)
+		ptd->status = -EINTR;
+	else
+		ptd->status = nvme_req(req)->status;
+
+	ptd->result = le64_to_cpu(nvme_req(req)->result.u64);
+	bio = ptd->bio;
+	/* setup task work if needed */
+	if (ptd->is_taskwork) {
+		int ret = nvme_add_task_work(ptioc->task, &ptioc->pt_work,
+				async_pt_update_work);
+		/* update failure if task-work could not be setup */
+		if (ret < 0) {
+			put_task_struct(ptioc->task);
+			ptioc->pt_complete(ptioc, ret);
+			kfree(ptd->meta);
+			kfree(ptd);
+		}
+	} else {
+		/* return status via callback, nothing else to update */
+		ptioc->pt_complete(ptioc, ptd->status);
+		kfree(ptd);
+	}
+
+	/* unmap pages, free bio, nvme command and request */
+	blk_rq_unmap_user(bio);
+	kfree(nvme_req(req)->cmd);
+	blk_mq_free_request(req);
+}
+
+
+void nvme_execute_passthru_rq_common(struct request *rq, int async)
 {
 	struct nvme_command *cmd = nvme_req(rq)->cmd;
 	struct nvme_ctrl *ctrl = nvme_req(rq)->ctrl;
@@ -1101,15 +1202,52 @@ void nvme_execute_passthru_rq(struct request *rq)
 	u32 effects;
 
 	effects = nvme_passthru_start(ctrl, ns, cmd->common.opcode);
-	blk_execute_rq(rq->q, disk, rq, 0);
+	if (!async)
+		blk_execute_rq(rq->q, disk, rq, 0);
+	else
+		blk_execute_rq_nowait(rq->q, disk, rq, 0, nvme_end_async_pt);
 	nvme_passthru_end(ctrl, effects);
 }
+
+void nvme_execute_passthru_rq(struct request *rq)
+{
+	return nvme_execute_passthru_rq_common(rq, 0);
+}
 EXPORT_SYMBOL_NS_GPL(nvme_execute_passthru_rq, NVME_TARGET_PASSTHRU);
 
+static int setup_async_pt_desc(struct request *rq, struct pt_ioctl_ctx *ptioc,
+		void __user *resptr, void __user *meta_buffer, void *meta,
+		unsigned meta_len, bool write, bool is_res64)
+{
+	struct async_pt_desc *ptd;
+
+	ptd = kzalloc(sizeof(struct async_pt_desc), GFP_KERNEL);
+	if (!ptd)
+		return -ENOMEM;
+
+	/* to free bio on completion, as req->bio will be null at that time */
+	ptd->bio = rq->bio;
+	ptd->res_ptr = resptr;
+	ptd->is_write = write;
+	ptd->is_res64 = is_res64;
+	if (meta) {
+		ptd->meta_ptr = meta_buffer;
+		ptd->meta = meta;
+		ptd->metalen = meta_len;
+	}
+	if (resptr)
+		ptd->is_taskwork = 1;
+
+	ptioc->ioc_data = ptd;
+	rq->end_io_data = ptioc;
+	return 0;
+}
+
 static int nvme_submit_user_cmd(struct request_queue *q,
 		struct nvme_command *cmd, void __user *ubuffer,
 		unsigned bufflen, void __user *meta_buffer, unsigned meta_len,
-		u32 meta_seed, u64 *result, unsigned timeout)
+		u32 meta_seed, u64 *result, unsigned timeout,
+		struct pt_ioctl_ctx *ptioc, bool is_res64)
 {
 	bool write = nvme_is_write(cmd);
 	struct nvme_ns *ns = q->queuedata;
@@ -1145,6 +1283,18 @@ static int nvme_submit_user_cmd(struct request_queue *q,
 		}
 	}
 
+	if (ptioc) { /* async handling */
+		ret = setup_async_pt_desc(req, ptioc, result, meta_buffer,
+			       meta, meta_len, write, is_res64);
+		if (ret) {
+			kfree(meta);
+			goto out_unmap;
+		}
+		/* send request for async processing */
+		nvme_execute_passthru_rq_common(req, 1);
+		return ret;
+	}
+	/* sync handling */
 	nvme_execute_passthru_rq(req);
 	if (nvme_req(req)->flags & NVME_REQ_CANCELLED)
 		ret = -EINTR;
@@ -1521,10 +1671,11 @@ static void __user *nvme_to_user_ptr(uintptr_t ptrval)
 	return (void __user *)ptrval;
 }
 
-static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
+static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio,
+			struct pt_ioctl_ctx *ptioc)
 {
 	struct nvme_user_io io;
-	struct nvme_command c;
+	struct nvme_command c, *cptr;
 	unsigned length, meta_len;
 	void __user *metadata;
 
@@ -1554,31 +1705,42 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
 			return -EINVAL;
 	}
 
-	memset(&c, 0, sizeof(c));
-	c.rw.opcode = io.opcode;
-	c.rw.flags = io.flags;
-	c.rw.nsid = cpu_to_le32(ns->head->ns_id);
-	c.rw.slba = cpu_to_le64(io.slba);
-	c.rw.length = cpu_to_le16(io.nblocks);
-	c.rw.control = cpu_to_le16(io.control);
-	c.rw.dsmgmt = cpu_to_le32(io.dsmgmt);
-	c.rw.reftag = cpu_to_le32(io.reftag);
-	c.rw.apptag = cpu_to_le16(io.apptag);
-	c.rw.appmask = cpu_to_le16(io.appmask);
-
-	return nvme_submit_user_cmd(ns->queue, &c,
+	if (!ptioc)
+		cptr = &c;
+	else { /* for async - allocate cmd dynamically */
+		cptr = kmalloc(sizeof(struct nvme_command), GFP_KERNEL);
+		if (!cptr)
+			return -ENOMEM;
+	}
+
+	memset(cptr, 0, sizeof(c));
+	cptr->rw.opcode = io.opcode;
+	cptr->rw.flags = io.flags;
+	cptr->rw.nsid = cpu_to_le32(ns->head->ns_id);
+	cptr->rw.slba = cpu_to_le64(io.slba);
+	cptr->rw.length = cpu_to_le16(io.nblocks);
+	cptr->rw.control = cpu_to_le16(io.control);
+	cptr->rw.dsmgmt = cpu_to_le32(io.dsmgmt);
+	cptr->rw.reftag = cpu_to_le32(io.reftag);
+	cptr->rw.apptag = cpu_to_le16(io.apptag);
+	cptr->rw.appmask = cpu_to_le16(io.appmask);
+
+	return nvme_submit_user_cmd(ns->queue, cptr,
 			nvme_to_user_ptr(io.addr), length,
-			metadata, meta_len, lower_32_bits(io.slba), NULL, 0);
+			metadata, meta_len, lower_32_bits(io.slba), NULL, 0,
+			ptioc, 0);
 }
 
 static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
-			struct nvme_passthru_cmd __user *ucmd)
+			struct nvme_passthru_cmd __user *ucmd,
+			struct pt_ioctl_ctx *ptioc)
 {
 	struct nvme_passthru_cmd cmd;
-	struct nvme_command c;
+	struct nvme_command c, *cptr;
 	unsigned timeout = 0;
 	u64 result;
 	int status;
+	void *resptr;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
@@ -1586,43 +1748,61 @@ static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
 		return -EFAULT;
 	if (cmd.flags)
 		return -EINVAL;
+	if (!ptioc) {
+		cptr = &c;
+		resptr = &result;
+	} else {
+		/*
+		 * for async - (a) allocate cmd dynamically
+		 * (b) use user-space result addr
+		 */
+		cptr = kmalloc(sizeof(struct nvme_command), GFP_KERNEL);
+		if (!cptr)
+			return -ENOMEM;
+		resptr = &ucmd->result;
+	}
 
-	memset(&c, 0, sizeof(c));
-	c.common.opcode = cmd.opcode;
-	c.common.flags = cmd.flags;
-	c.common.nsid = cpu_to_le32(cmd.nsid);
-	c.common.cdw2[0] = cpu_to_le32(cmd.cdw2);
-	c.common.cdw2[1] = cpu_to_le32(cmd.cdw3);
-	c.common.cdw10 = cpu_to_le32(cmd.cdw10);
-	c.common.cdw11 = cpu_to_le32(cmd.cdw11);
-	c.common.cdw12 = cpu_to_le32(cmd.cdw12);
-	c.common.cdw13 = cpu_to_le32(cmd.cdw13);
-	c.common.cdw14 = cpu_to_le32(cmd.cdw14);
-	c.common.cdw15 = cpu_to_le32(cmd.cdw15);
+	memset(cptr, 0, sizeof(c));
+	cptr->common.opcode = cmd.opcode;
+	cptr->common.flags = cmd.flags;
+	cptr->common.nsid = cpu_to_le32(cmd.nsid);
+	cptr->common.cdw2[0] = cpu_to_le32(cmd.cdw2);
+	cptr->common.cdw2[1] = cpu_to_le32(cmd.cdw3);
+	cptr->common.cdw10 = cpu_to_le32(cmd.cdw10);
+	cptr->common.cdw11 = cpu_to_le32(cmd.cdw11);
+	cptr->common.cdw12 = cpu_to_le32(cmd.cdw12);
+	cptr->common.cdw13 = cpu_to_le32(cmd.cdw13);
+	cptr->common.cdw14 = cpu_to_le32(cmd.cdw14);
+	cptr->common.cdw15 = cpu_to_le32(cmd.cdw15);
 
 	if (cmd.timeout_ms)
 		timeout = msecs_to_jiffies(cmd.timeout_ms);
 
-	status = nvme_submit_user_cmd(ns ? ns->queue : ctrl->admin_q, &c,
+	status = nvme_submit_user_cmd(ns ? ns->queue : ctrl->admin_q, cptr,
 			nvme_to_user_ptr(cmd.addr), cmd.data_len,
 			nvme_to_user_ptr(cmd.metadata), cmd.metadata_len,
-			0, &result, timeout);
+			0, resptr, timeout, ptioc, 0);
 
-	if (status >= 0) {
+	if (!ptioc && status >= 0) {
 		if (put_user(result, &ucmd->result))
 			return -EFAULT;
 	}
+	/* async case, free cmd in case of error */
+	if (ptioc && status < 0)
+		kfree(cptr);
 
 	return status;
 }
 
 static int nvme_user_cmd64(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
-			struct nvme_passthru_cmd64 __user *ucmd)
+			struct nvme_passthru_cmd64 __user *ucmd,
+			struct pt_ioctl_ctx *ptioc)
 {
 	struct nvme_passthru_cmd64 cmd;
-	struct nvme_command c;
+	struct nvme_command c, *cptr;
 	unsigned timeout = 0;
 	int status;
+	void *resptr;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
@@ -1631,31 +1811,43 @@ static int nvme_user_cmd64(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
 	if (cmd.flags)
 		return -EINVAL;
 
-	memset(&c, 0, sizeof(c));
-	c.common.opcode = cmd.opcode;
-	c.common.flags = cmd.flags;
-	c.common.nsid = cpu_to_le32(cmd.nsid);
-	c.common.cdw2[0] = cpu_to_le32(cmd.cdw2);
-	c.common.cdw2[1] = cpu_to_le32(cmd.cdw3);
-	c.common.cdw10 = cpu_to_le32(cmd.cdw10);
-	c.common.cdw11 = cpu_to_le32(cmd.cdw11);
-	c.common.cdw12 = cpu_to_le32(cmd.cdw12);
-	c.common.cdw13 = cpu_to_le32(cmd.cdw13);
-	c.common.cdw14 = cpu_to_le32(cmd.cdw14);
-	c.common.cdw15 = cpu_to_le32(cmd.cdw15);
+	if (!ptioc) {
+		cptr = &c;
+		resptr = &cmd.result;
+	} else {
+		cptr = kmalloc(sizeof(struct nvme_command), GFP_KERNEL);
+		if (!cptr)
+			return -ENOMEM;
+		resptr = &ucmd->result;
+	}
+
+	memset(cptr, 0, sizeof(struct nvme_command));
+	cptr->common.opcode = cmd.opcode;
+	cptr->common.flags = cmd.flags;
+	cptr->common.nsid = cpu_to_le32(cmd.nsid);
+	cptr->common.cdw2[0] = cpu_to_le32(cmd.cdw2);
+	cptr->common.cdw2[1] = cpu_to_le32(cmd.cdw3);
+	cptr->common.cdw10 = cpu_to_le32(cmd.cdw10);
+	cptr->common.cdw11 = cpu_to_le32(cmd.cdw11);
+	cptr->common.cdw12 = cpu_to_le32(cmd.cdw12);
+	cptr->common.cdw13 = cpu_to_le32(cmd.cdw13);
+	cptr->common.cdw14 = cpu_to_le32(cmd.cdw14);
+	cptr->common.cdw15 = cpu_to_le32(cmd.cdw15);
 
 	if (cmd.timeout_ms)
 		timeout = msecs_to_jiffies(cmd.timeout_ms);
 
-	status = nvme_submit_user_cmd(ns ? ns->queue : ctrl->admin_q, &c,
+	status = nvme_submit_user_cmd(ns ? ns->queue : ctrl->admin_q, cptr,
 			nvme_to_user_ptr(cmd.addr), cmd.data_len,
 			nvme_to_user_ptr(cmd.metadata), cmd.metadata_len,
-			0, &cmd.result, timeout);
+			0, resptr, timeout, ptioc, 1);
 
-	if (status >= 0) {
+	if (!ptioc && status >= 0) {
 		if (put_user(cmd.result, &ucmd->result))
 			return -EFAULT;
 	}
+	if (ptioc && status < 0)
+		kfree(cptr);
 
 	return status;
 }
@@ -1702,7 +1894,8 @@ static bool is_ctrl_ioctl(unsigned int cmd)
 static int nvme_handle_ctrl_ioctl(struct nvme_ns *ns, unsigned int cmd,
 				  void __user *argp,
 				  struct nvme_ns_head *head,
-				  int srcu_idx)
+				  int srcu_idx,
+				  struct pt_ioctl_ctx *ptioc)
 {
 	struct nvme_ctrl *ctrl = ns->ctrl;
 	int ret;
@@ -1712,21 +1905,24 @@ static int nvme_handle_ctrl_ioctl(struct nvme_ns *ns, unsigned int cmd,
 
 	switch (cmd) {
 	case NVME_IOCTL_ADMIN_CMD:
-		ret = nvme_user_cmd(ctrl, NULL, argp);
+		ret = nvme_user_cmd(ctrl, NULL, argp, ptioc);
 		break;
 	case NVME_IOCTL_ADMIN64_CMD:
-		ret = nvme_user_cmd64(ctrl, NULL, argp);
+		ret = nvme_user_cmd64(ctrl, NULL, argp, ptioc);
 		break;
 	default:
-		ret = sed_ioctl(ctrl->opal_dev, cmd, argp);
+		if (!ptioc)
+			ret = sed_ioctl(ctrl->opal_dev, cmd, argp);
+		else
+			ret = -EOPNOTSUPP; /* RFP: no support for now */
 		break;
 	}
 	nvme_put_ctrl(ctrl);
 	return ret;
 }
 
-static int nvme_ioctl(struct block_device *bdev, fmode_t mode,
-		unsigned int cmd, unsigned long arg)
+static int nvme_async_ioctl(struct block_device *bdev, fmode_t mode,
+		unsigned int cmd, unsigned long arg, struct pt_ioctl_ctx *ptioc)
 {
 	struct nvme_ns_head *head = NULL;
 	void __user *argp = (void __user *)arg;
@@ -1743,33 +1939,49 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode,
 	 * deadlock when deleting namespaces using the passthrough interface.
 	 */
 	if (is_ctrl_ioctl(cmd))
-		return nvme_handle_ctrl_ioctl(ns, cmd, argp, head, srcu_idx);
+		return nvme_handle_ctrl_ioctl(ns, cmd, argp, head, srcu_idx, ptioc);
 
 	switch (cmd) {
 	case NVME_IOCTL_ID:
 		force_successful_syscall_return();
 		ret = ns->head->ns_id;
+		if (ptioc)
+			goto put_ns; /* return in sync fashion always */
 		break;
 	case NVME_IOCTL_IO_CMD:
-		ret = nvme_user_cmd(ns->ctrl, ns, argp);
+		ret = nvme_user_cmd(ns->ctrl, ns, argp, ptioc);
 		break;
 	case NVME_IOCTL_SUBMIT_IO:
-		ret = nvme_submit_io(ns, argp);
+		ret = nvme_submit_io(ns, argp, ptioc);
 		break;
 	case NVME_IOCTL_IO64_CMD:
-		ret = nvme_user_cmd64(ns->ctrl, ns, argp);
+		ret = nvme_user_cmd64(ns->ctrl, ns, argp, ptioc);
 		break;
 	default:
+		if (ptioc) {
+			/* RFP- don't support this for now */
+			ret = -EOPNOTSUPP;
+			break;
+		}
 		if (ns->ndev)
 			ret = nvme_nvm_ioctl(ns, cmd, arg);
 		else
 			ret = -ENOTTY;
 	}
-
+	/* if there is no error, return queued for async-ioctl */
+	if (ptioc && ret >= 0)
+		ret = -EIOCBQUEUED;
+ put_ns:
 	nvme_put_ns_from_disk(head, srcu_idx);
 	return ret;
 }
 
+static int nvme_ioctl(struct block_device *bdev, fmode_t mode,
+		unsigned int cmd, unsigned long arg)
+{
+	return nvme_async_ioctl(bdev, mode, cmd, arg, NULL);
+}
+
 #ifdef CONFIG_COMPAT
 struct nvme_user_io32 {
 	__u8	opcode;
@@ -2324,6 +2536,7 @@ EXPORT_SYMBOL_GPL(nvme_sec_submit);
 static const struct block_device_operations nvme_bdev_ops = {
 	.owner		= THIS_MODULE,
 	.ioctl		= nvme_ioctl,
+	.async_ioctl	= nvme_async_ioctl,
 	.compat_ioctl	= nvme_compat_ioctl,
 	.open		= nvme_open,
 	.release	= nvme_release,
@@ -3261,7 +3474,7 @@ static int nvme_dev_user_cmd(struct nvme_ctrl *ctrl, void __user *argp)
 	kref_get(&ns->kref);
 	up_read(&ctrl->namespaces_rwsem);
 
-	ret = nvme_user_cmd(ctrl, ns, argp);
+	ret = nvme_user_cmd(ctrl, ns, argp, NULL);
 	nvme_put_ns(ns);
 	return ret;
 
@@ -3278,9 +3491,9 @@ static long nvme_dev_ioctl(struct file *file, unsigned int cmd,
 
 	switch (cmd) {
 	case NVME_IOCTL_ADMIN_CMD:
-		return nvme_user_cmd(ctrl, NULL, argp);
+		return nvme_user_cmd(ctrl, NULL, argp, NULL);
 	case NVME_IOCTL_ADMIN64_CMD:
-		return nvme_user_cmd64(ctrl, NULL, argp);
+		return nvme_user_cmd64(ctrl, NULL, argp, NULL);
 	case NVME_IOCTL_IO_CMD:
 		return nvme_dev_user_cmd(ctrl, argp);
 	case NVME_IOCTL_RESET:
-- 
2.25.1



From kbusch at kernel.org  Wed Jan 27 10:05:26 2021
From: kbusch at kernel.org (Keith Busch)
Date: Thu, 28 Jan 2021 00:05:26 +0900
Subject: [PATCH 1/5] nvme: add NVME_REQ_CANCELLED flag in
 nvme_cancel_request()
In-Reply-To: <20210127103326.16191-2-hare@suse.de>
References: <20210127103326.16191-1-hare@suse.de>
 <20210127103326.16191-2-hare@suse.de>
Message-ID: <20210127150526.GC23059@redsun51.ssa.fujisawa.hgst.com>

On Wed, Jan 27, 2021 at 11:33:22AM +0100, Hannes Reinecke wrote:
> NVME_REQ_CANCELLED is translated into -EINTR in nvme_submit_sync_cmd(),
> so we should be setting this flags during nvme_cancel_request() to
> ensure that the callers to nvme_submit_sync_cmd() will get the correct
> error code when the controller is reset.
> 
> Signed-off-by: Hannes Reinecke <hare at suse.de>
> Reviewed-by: Daniel Wagner <dwagner at suse.de>

Looks good,

Reviewed-by: Keith Busch <kbusch at kernel.org>


From kbusch at kernel.org  Wed Jan 27 10:09:17 2021
From: kbusch at kernel.org (Keith Busch)
Date: Thu, 28 Jan 2021 00:09:17 +0900
Subject: [PATCHv2 0/5][RESEND] Fixup return value for
 nvme_submit_sync_cmd()
In-Reply-To: <20210127103326.16191-1-hare@suse.de>
References: <20210127103326.16191-1-hare@suse.de>
Message-ID: <20210127150917.GD23059@redsun51.ssa.fujisawa.hgst.com>

On Wed, Jan 27, 2021 at 11:33:21AM +0100, Hannes Reinecke wrote:
> Hi all,
> 
> here are some small patches for fixing up the return value of nvme_submit_sync_cmd().
> As Keith correctly noted, nvme_submit_sync_cmd() should be returning
> an error if the command could not be performed; however, currently
> only pci does that.
> So we need to fix up nvme_cancel_request() to return an -EINTR
> on any pending sync commands during reset.
> And modify nvme-fc to return the same nvme status after timing out
> or cancelling requests.
> Plus, finally, adding a new flag 'NVME_REQ_TIMEOUT' to indicate
> that a command had been aborted due to a timeout, and translates that
> back into -ETIMEDOUT as a return code for nvme_submit_sync_cmd().

Mostly looks good, but I'm not sure I understand the NVME_REQ_TIMEOUT
flag at the end. That appears to be serving the same purpose as the
"CANCELLED" flag, no?


From joshi.k at samsung.com  Wed Jan 27 10:00:29 2021
From: joshi.k at samsung.com (Kanchan Joshi)
Date: Wed, 27 Jan 2021 20:30:29 +0530
Subject: [RFC PATCH 4/4] io_uring: add async passthrough ioctl support
In-Reply-To: <20210127150029.13766-1-joshi.k@samsung.com>
References: <20210127150029.13766-1-joshi.k@samsung.com>
 <CGME20210127150156epcas5p26cdf368e4ff6bffb132fa1c7f9430653@epcas5p2.samsung.com>
Message-ID: <20210127150029.13766-5-joshi.k@samsung.com>

Introduce IORING_OP_IOCTL_PT for async ioctl. It skips entering into
block-layer and reaches to underlying block-driver managing the
block-device. This is done by calling newly introduced "async_ioctl"
block-device operation.
The requested operation may be completed synchronously, and in that case
CQE is updated on the fly. For asynchronous update, lower-layer calls
the completion-callback supplied by io-uring.

Signed-off-by: Kanchan Joshi <joshi.k at samsung.com>
Signed-off-by: Anuj Gupta <anuj20.g at samsung.com>
---
 fs/io_uring.c                 | 77 +++++++++++++++++++++++++++++++++++
 include/uapi/linux/io_uring.h |  7 +++-
 2 files changed, 83 insertions(+), 1 deletion(-)

diff --git a/fs/io_uring.c b/fs/io_uring.c
index 985a9e3f976d..c15852dfb727 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -468,6 +468,19 @@ struct io_rw {
 	u64				len;
 };
 
+/*
+ * passthru ioctl skips block-layer and reaches to block device driver via
+ * async_ioctl() block-dev operation.
+ */
+struct io_pt_ioctl {
+	struct file			*file;
+	/* arg and cmd like regular ioctl */
+	u64				arg;
+	u32				cmd;
+	/* defined by block layer */
+	struct pt_ioctl_ctx		ioctx;
+};
+
 struct io_connect {
 	struct file			*file;
 	struct sockaddr __user		*addr;
@@ -699,6 +712,7 @@ struct io_kiocb {
 		struct io_shutdown	shutdown;
 		struct io_rename	rename;
 		struct io_unlink	unlink;
+		struct io_pt_ioctl	ptioctl;
 		/* use only after cleaning per-op data, see io_clean_op() */
 		struct io_completion	compl;
 	};
@@ -824,6 +838,10 @@ static const struct io_op_def io_op_defs[] = {
 		.needs_file		= 1,
 		.work_flags		= IO_WQ_WORK_BLKCG,
 	},
+	[IORING_OP_IOCTL_PT] = {
+		.needs_file		= 1,
+		.work_flags		= IO_WQ_WORK_MM,
+	},
 	[IORING_OP_READ_FIXED] = {
 		.needs_file		= 1,
 		.unbound_nonreg_file	= 1,
@@ -3704,6 +3722,60 @@ static int io_write(struct io_kiocb *req, bool force_nonblock,
 	return ret;
 }
 
+static int io_pt_ioctl_prep(struct io_kiocb *req,
+			    const struct io_uring_sqe *sqe)
+{
+	unsigned int cmd = READ_ONCE(sqe->ioctl_cmd);
+	unsigned long arg = READ_ONCE(sqe->ioctl_arg);
+	struct io_ring_ctx *ctx = req->ctx;
+	struct block_device *bdev = I_BDEV(req->file->f_mapping->host);
+	struct gendisk *disk = NULL;
+
+	disk = bdev->bd_disk;
+	if (!disk || !disk->fops || !disk->fops->async_ioctl)
+		return -EOPNOTSUPP;
+	/* for sqpoll, use sqo_task */
+	if (ctx->flags & IORING_SETUP_SQPOLL)
+		req->ptioctl.ioctx.task = ctx->sqo_task;
+	else
+		req->ptioctl.ioctx.task = current;
+
+	req->ptioctl.arg = arg;
+	req->ptioctl.cmd = cmd;
+	return 0;
+}
+
+void pt_complete(struct pt_ioctl_ctx *ptioc, long ret)
+{
+	struct io_kiocb *req = container_of(ptioc, struct io_kiocb, ptioctl.ioctx);
+
+	if (ret < 0)
+		req_set_fail_links(req);
+	io_req_complete(req, ret);
+}
+
+static int io_pt_ioctl(struct io_kiocb *req, bool force_nonblock)
+{
+	long ret = 0;
+	struct block_device *bdev = I_BDEV(req->file->f_mapping->host);
+	fmode_t mode = req->file->f_mode;
+	struct gendisk *disk = NULL;
+
+	disk = bdev->bd_disk;
+	/* set up callback for async */
+	req->ptioctl.ioctx.pt_complete = pt_complete;
+
+	ret = disk->fops->async_ioctl(bdev, mode, req->ptioctl.cmd,
+				req->ptioctl.arg, &req->ptioctl.ioctx);
+	if (ret == -EIOCBQUEUED) /*async completion */
+		return 0;
+	if (ret < 0)
+		req_set_fail_links(req);
+
+	io_req_complete(req, ret);
+	return 0;
+}
+
 static int io_renameat_prep(struct io_kiocb *req,
 			    const struct io_uring_sqe *sqe)
 {
@@ -6078,6 +6150,8 @@ static int io_req_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 		return io_renameat_prep(req, sqe);
 	case IORING_OP_UNLINKAT:
 		return io_unlinkat_prep(req, sqe);
+	case IORING_OP_IOCTL_PT:
+		return io_pt_ioctl_prep(req, sqe);
 	}
 
 	printk_once(KERN_WARNING "io_uring: unhandled opcode %d\n",
@@ -6337,6 +6411,9 @@ static int io_issue_sqe(struct io_kiocb *req, bool force_nonblock,
 	case IORING_OP_UNLINKAT:
 		ret = io_unlinkat(req, force_nonblock);
 		break;
+	case IORING_OP_IOCTL_PT:
+		ret = io_pt_ioctl(req, force_nonblock);
+		break;
 	default:
 		ret = -EINVAL;
 		break;
diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h
index d31a2a1e8ef9..60671e2b00ba 100644
--- a/include/uapi/linux/io_uring.h
+++ b/include/uapi/linux/io_uring.h
@@ -22,12 +22,16 @@ struct io_uring_sqe {
 	union {
 		__u64	off;	/* offset into file */
 		__u64	addr2;
+		__u64	ioctl_arg;
 	};
 	union {
 		__u64	addr;	/* pointer to buffer or iovecs */
 		__u64	splice_off_in;
 	};
-	__u32	len;		/* buffer size or number of iovecs */
+	union {
+		__u32	len;	/* buffer size or number of iovecs */
+		__u32	ioctl_cmd;
+	};
 	union {
 		__kernel_rwf_t	rw_flags;
 		__u32		fsync_flags;
@@ -137,6 +141,7 @@ enum {
 	IORING_OP_SHUTDOWN,
 	IORING_OP_RENAMEAT,
 	IORING_OP_UNLINKAT,
+	IORING_OP_IOCTL_PT,
 
 	/* this goes last, obviously */
 	IORING_OP_LAST,
-- 
2.25.1



From asml.silence at gmail.com  Wed Jan 27 10:42:46 2021
From: asml.silence at gmail.com (Pavel Begunkov)
Date: Wed, 27 Jan 2021 15:42:46 +0000
Subject: [RFC PATCH 0/4] Asynchronous passthrough ioctl
In-Reply-To: <20210127150029.13766-1-joshi.k@samsung.com>
References: <CGME20210127150134epcas5p251fc1de3ff3581dd4c68b3fbe0b9dd91@epcas5p2.samsung.com>
 <20210127150029.13766-1-joshi.k@samsung.com>
Message-ID: <489691ce-3b1e-30ce-9f72-d32389e33901@gmail.com>

On 27/01/2021 15:00, Kanchan Joshi wrote:
> This RFC patchset adds asynchronous ioctl capability for NVMe devices.
> Purpose of RFC is to get the feedback and optimize the path.
> 
> At the uppermost io-uring layer, a new opcode IORING_OP_IOCTL_PT is
> presented to user-space applications. Like regular-ioctl, it takes
> ioctl opcode and an optional argument (ioctl-specific input/output
> parameter). Unlike regular-ioctl, it is made to skip the block-layer
> and reach directly to the underlying driver (nvme in the case of this
> patchset). This path between io-uring and nvme is via a newly
> introduced block-device operation "async_ioctl". This operation
> expects io-uring to supply a callback function which can be used to
> report completion at later stage.
> 
> For a regular ioctl, NVMe driver submits the command to the device and
> the submitter (task) is made to wait until completion arrives. For
> async-ioctl, completion is decoupled from submission. Submitter goes
> back to its business without waiting for nvme-completion. When
> nvme-completion arrives, it informs io-uring via the registered
> completion-handler. But some ioctls may require updating certain
> ioctl-specific fields which can be accessed only in context of the
> submitter task. For that reason, NVMe driver uses task-work infra for
> that ioctl-specific update. Since task-work is not exported, it cannot
> be referenced when nvme is compiled as a module. Therefore, one of the
> patch exports task-work API.
> 
> Here goes example of usage (pseudo-code).
> Actual nvme-cli source, modified to issue all ioctls via this opcode
> is present at-
> https://github.com/joshkan/nvme-cli/commit/a008a733f24ab5593e7874cfbc69ee04e88068c5

see https://git.kernel.dk/cgit/linux-block/log/?h=io_uring-fops

Looks like good time to bring that branch/discussion back

> 
> With regular ioctl-
> int nvme_submit_passthru(int fd, unsigned long ioctl_cmd,
>                          struct nvme_passthru_cmd *cmd)
> {
> 	return ioctl(fd, ioctl_cmd, cmd);
> }
> 
> With uring passthru ioctl-
> int nvme_submit_passthru(int fd, unsigned long ioctl_cmd,
>                          struct nvme_passthru_cmd *cmd)
> {
> 	return uring_ioctl(fd, ioctl_cmd, cmd);
> }
> int uring_ioctl(int fd, unsinged long cmd, u64 arg)
> {
> 	sqe = io_uring_get_sqe(ring);
> 
> 	/* prepare sqe */
> 	sqe->fd = fd;
> 	sqe->opcode = IORING_OP_IOCTL_PT;
> 	sqe->ioctl_cmd = cmd;
> 	sqe->ioctl_arg = arg;
> 
> 	/* submit sqe */
> 	io_uring_submit(ring);
> 
> 	/* reap completion and obtain result */
> 	io_uring_wait_cqe(ring, &cqe);
> 	printf("ioctl result =%d\n", cqe->res)
> }
> 
> Kanchan Joshi (4):
>   block: introduce async ioctl operation
>   kernel: export task_work_add
>   nvme: add async ioctl support
>   io_uring: add async passthrough ioctl support
> 
>  drivers/nvme/host/core.c      | 347 +++++++++++++++++++++++++++-------
>  fs/io_uring.c                 |  77 ++++++++
>  include/linux/blkdev.h        |  12 ++
>  include/uapi/linux/io_uring.h |   7 +-
>  kernel/task_work.c            |   2 +-
>  5 files changed, 376 insertions(+), 69 deletions(-)
> 

-- 
Pavel Begunkov


From asml.silence at gmail.com  Wed Jan 27 10:53:19 2021
From: asml.silence at gmail.com (Pavel Begunkov)
Date: Wed, 27 Jan 2021 15:53:19 +0000
Subject: [RFC PATCH 0/4] Asynchronous passthrough ioctl
In-Reply-To: <489691ce-3b1e-30ce-9f72-d32389e33901@gmail.com>
References: <CGME20210127150134epcas5p251fc1de3ff3581dd4c68b3fbe0b9dd91@epcas5p2.samsung.com>
 <20210127150029.13766-1-joshi.k@samsung.com>
 <489691ce-3b1e-30ce-9f72-d32389e33901@gmail.com>
Message-ID: <a287bd9e-3474-83a4-e5c2-98df17214dc7@gmail.com>

On 27/01/2021 15:42, Pavel Begunkov wrote:
> On 27/01/2021 15:00, Kanchan Joshi wrote:
>> This RFC patchset adds asynchronous ioctl capability for NVMe devices.
>> Purpose of RFC is to get the feedback and optimize the path.
>>
>> At the uppermost io-uring layer, a new opcode IORING_OP_IOCTL_PT is
>> presented to user-space applications. Like regular-ioctl, it takes
>> ioctl opcode and an optional argument (ioctl-specific input/output
>> parameter). Unlike regular-ioctl, it is made to skip the block-layer
>> and reach directly to the underlying driver (nvme in the case of this
>> patchset). This path between io-uring and nvme is via a newly
>> introduced block-device operation "async_ioctl". This operation
>> expects io-uring to supply a callback function which can be used to
>> report completion at later stage.
>>
>> For a regular ioctl, NVMe driver submits the command to the device and
>> the submitter (task) is made to wait until completion arrives. For
>> async-ioctl, completion is decoupled from submission. Submitter goes
>> back to its business without waiting for nvme-completion. When
>> nvme-completion arrives, it informs io-uring via the registered
>> completion-handler. But some ioctls may require updating certain
>> ioctl-specific fields which can be accessed only in context of the
>> submitter task. For that reason, NVMe driver uses task-work infra for
>> that ioctl-specific update. Since task-work is not exported, it cannot
>> be referenced when nvme is compiled as a module. Therefore, one of the
>> patch exports task-work API.
>>
>> Here goes example of usage (pseudo-code).
>> Actual nvme-cli source, modified to issue all ioctls via this opcode
>> is present at-
>> https://github.com/joshkan/nvme-cli/commit/a008a733f24ab5593e7874cfbc69ee04e88068c5
> 
> see https://git.kernel.dk/cgit/linux-block/log/?h=io_uring-fops
> 
> Looks like good time to bring that branch/discussion back

a bit more context:
https://github.com/axboe/liburing/issues/270

-- 
Pavel Begunkov


From hch at lst.de  Wed Jan 27 11:35:55 2021
From: hch at lst.de (Christoph Hellwig)
Date: Wed, 27 Jan 2021 17:35:55 +0100
Subject: [PATCHv2] nvme/hwmon: rework to avoid devm allocation
In-Reply-To: <efddf566-a5a1-cda0-5fec-5e8a1d6bffb3@roeck-us.net>
References: <20210119064318.124415-1-hare@suse.de>
 <20210119145632.GD54031@roeck-us.net>
 <1093bedb-9b6d-b365-85d0-de8ef7eceb95@suse.de>
 <efddf566-a5a1-cda0-5fec-5e8a1d6bffb3@roeck-us.net>
Message-ID: <20210127163555.GA22717@lst.de>

On Tue, Jan 19, 2021 at 09:54:30PM -0800, Guenter Roeck wrote:
> It needs lm-sensors version 3.5.0 or later. Older versions
> don't support a device hierarchy.

Hannes, did you get a chance to test this with lm-sensors?


From hch at lst.de  Wed Jan 27 11:40:20 2021
From: hch at lst.de (Christoph Hellwig)
Date: Wed, 27 Jan 2021 17:40:20 +0100
Subject: [PATCH v4 1/5] blk-mq: introduce blk_mq_set_request_complete
In-Reply-To: <20210126081539.13320-2-lengchao@huawei.com>
References: <20210126081539.13320-1-lengchao@huawei.com>
 <20210126081539.13320-2-lengchao@huawei.com>
Message-ID: <20210127164020.GA23417@lst.de>

> +static inline void blk_mq_set_request_complete(struct request *rq)
> +{
> +	WRITE_ONCE(rq->state, MQ_RQ_COMPLETE);
> +}

This function needs a detailed comment explaining the use case.
Otherwise we'll get lots of driver abuses.


From hch at lst.de  Wed Jan 27 11:49:36 2021
From: hch at lst.de (Christoph Hellwig)
Date: Wed, 27 Jan 2021 17:49:36 +0100
Subject: [PATCH] nvme-pci: add write-zeores SPCC quirk
In-Reply-To: <20210126051916.3271-1-chaitanya.kulkarni@wdc.com>
References: <20210126051916.3271-1-chaitanya.kulkarni@wdc.com>
Message-ID: <20210127164936.GA24228@lst.de>

Thanks,

applied to nvme-5.11.


From hch at lst.de  Wed Jan 27 11:49:47 2021
From: hch at lst.de (Christoph Hellwig)
Date: Wed, 27 Jan 2021 17:49:47 +0100
Subject: [PATCH v2] nvme-multipath: Early exit if no path is available
In-Reply-To: <20210127103033.15318-1-dwagner@suse.de>
References: <20210127103033.15318-1-dwagner@suse.de>
Message-ID: <20210127164947.GB24228@lst.de>

Thanks,

applied to nvme-5.11.


From axboe at kernel.dk  Wed Jan 27 12:09:19 2021
From: axboe at kernel.dk (Jens Axboe)
Date: Wed, 27 Jan 2021 10:09:19 -0700
Subject: [PATCH] nvme-core: check bdev value for NULL
In-Reply-To: <20210127071344.GA21223@lst.de>
References: <20210127053738.4922-1-chaitanya.kulkarni@wdc.com>
 <20210127071344.GA21223@lst.de>
Message-ID: <683a593e-a5f2-0e09-2ad1-c2527946b253@kernel.dk>

On 1/27/21 12:13 AM, Christoph Hellwig wrote:
> Looks good:
> 
> Reviewed-by: Christoph Hellwig <hch at lst.de>
> 
> Jens, can you pick this up as it fixes an issue I introduced in
> for-5.12/block?

I can, I'll add the fixes tag too.

-- 
Jens Axboe



From hch at lst.de  Wed Jan 27 12:46:06 2021
From: hch at lst.de (Christoph Hellwig)
Date: Wed, 27 Jan 2021 18:46:06 +0100
Subject: [PATCH] nvme: trace: parse format nvm command in detail
In-Reply-To: <20210104155343.GA26034@michal-desk>
References: <20210104155343.GA26034@michal-desk>
Message-ID: <20210127174606.GA28180@lst.de>

Thanks,

applied to nvme-5.12.



From hch at lst.de  Wed Jan 27 12:46:18 2021
From: hch at lst.de (Christoph Hellwig)
Date: Wed, 27 Jan 2021 18:46:18 +0100
Subject: [PATCH 0/5] add clean action for failed reconnection
In-Reply-To: <20210121033240.31906-1-lengchao@huawei.com>
References: <20210121033240.31906-1-lengchao@huawei.com>
Message-ID: <20210127174618.GB28180@lst.de>

Thanks,

applied to nvme-5.12.


From hch at lst.de  Wed Jan 27 12:46:32 2021
From: hch at lst.de (Christoph Hellwig)
Date: Wed, 27 Jan 2021 18:46:32 +0100
Subject: [PATCH] nvme: add tracing of zns commands
In-Reply-To: <46eeed2fcf2530d02fe5727a0a91a6e4675f6edd.1611683161.git.johannes.thumshirn@wdc.com>
References: <46eeed2fcf2530d02fe5727a0a91a6e4675f6edd.1611683161.git.johannes.thumshirn@wdc.com>
Message-ID: <20210127174632.GC28180@lst.de>

Thanks,

applied to nvme-5.12.


From hch at lst.de  Wed Jan 27 12:46:56 2021
From: hch at lst.de (Christoph Hellwig)
Date: Wed, 27 Jan 2021 18:46:56 +0100
Subject: [PATCH 1/2] nvme: update enumerations for status codes
In-Reply-To: <20210121090948.8027-3-mgurtovoy@nvidia.com>
References: <20210121090948.8027-1-mgurtovoy@nvidia.com>
 <20210121090948.8027-3-mgurtovoy@nvidia.com>
Message-ID: <20210127174656.GE28180@lst.de>

Thanks,

applied to nvme-5.12.


From hch at lst.de  Wed Jan 27 12:47:17 2021
From: hch at lst.de (Christoph Hellwig)
Date: Wed, 27 Jan 2021 18:47:17 +0100
Subject: [PATCH 2/2] nvme: resync header file with common nvme-cli tool
In-Reply-To: <20210121090948.8027-4-mgurtovoy@nvidia.com>
References: <20210121090948.8027-1-mgurtovoy@nvidia.com>
 <20210121090948.8027-4-mgurtovoy@nvidia.com>
Message-ID: <20210127174717.GF28180@lst.de>

Can you respin this against the nvme-5.12 branch?  As-is git-am is not
happy with it.



From jxgao at google.com  Wed Jan 27 19:38:26 2021
From: jxgao at google.com (Jianxiong Gao)
Date: Wed, 27 Jan 2021 16:38:26 -0800
Subject: [PATCH 0/3] Adding offset keeping option when mapping data via
 SWIOTLB.*
Message-ID: <20210128003829.1892018-1-jxgao@google.com>

NVMe driver and other applications may depend on the data offset
to operate correctly. Currently when unaligned data is mapped via
SWIOTLB, the data is mapped as slab aligned with the SWIOTLB. This
patch adds an option to make sure the mapped data preserves its
offset of the orginal addrss.

Without the patch when creating xfs formatted disk on NVMe backends,
with swiotlb=force in kernel boot option, creates the following error:
meta-data=/dev/nvme2n1           isize=512    agcount=4, agsize=131072 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=0, rmapbt=0, refl
ink=0
data     =                       bsize=4096   blocks=524288, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=1
log      =internal log           bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
mkfs.xfs: pwrite failed: Input/output error

Jianxiong Gao (3):
  Adding page_offset_mask to device_dma_parameters
  Add swiotlb offset preserving mapping when
    dma_dma_parameters->page_offset_mask is non zero.
  Adding device_dma_parameters->offset_preserve_mask to NVMe driver.

 drivers/nvme/host/pci.c     |  4 ++++
 include/linux/device.h      |  1 +
 include/linux/dma-mapping.h | 17 +++++++++++++++++
 kernel/dma/swiotlb.c        | 16 +++++++++++++++-
 4 files changed, 37 insertions(+), 1 deletion(-)

-- 
2.27.0



From jxgao at google.com  Wed Jan 27 19:38:27 2021
From: jxgao at google.com (Jianxiong Gao)
Date: Wed, 27 Jan 2021 16:38:27 -0800
Subject: [PATCH 1/3] Adding page_offset_mask to device_dma_parameters
In-Reply-To: <20210128003829.1892018-1-jxgao@google.com>
References: <20210128003829.1892018-1-jxgao@google.com>
Message-ID: <20210128003829.1892018-2-jxgao@google.com>

Some devices rely on the address offset in a page to function
correctly (NVMe driver as an example). These devices may use
a different page size than the Linux kernel. The address offset
has to be preserved upon mapping, and in order to do so, we
need to record the page_offset_mask first.

Signed-off-by: Jianxiong Gao <jxgao at google.com>
---
 include/linux/device.h      |  1 +
 include/linux/dma-mapping.h | 17 +++++++++++++++++
 2 files changed, 18 insertions(+)

diff --git a/include/linux/device.h b/include/linux/device.h
index 1779f90eeb4c..f44e0659fc66 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -292,6 +292,7 @@ struct device_dma_parameters {
 	 */
 	unsigned int max_segment_size;
 	unsigned long segment_boundary_mask;
+	unsigned int page_offset_mask;
 };
 
 /**
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index 2e49996a8f39..5529a31fefba 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -500,6 +500,23 @@ static inline int dma_set_seg_boundary(struct device *dev, unsigned long mask)
 	return -EIO;
 }
 
+static inline unsigned int dma_get_page_offset_mask(struct device *dev)
+{
+	if (dev->dma_parms)
+		return dev->dma_parms->page_offset_mask;
+	return 0;
+}
+
+static inline int dma_set_page_offset_mask(struct device *dev,
+		unsigned int page_offset_mask)
+{
+	if (dev->dma_parms) {
+		dev->dma_parms->page_offset_mask = page_offset_mask;
+		return 0;
+	}
+	return -EIO;
+}
+
 static inline int dma_get_cache_alignment(void)
 {
 #ifdef ARCH_DMA_MINALIGN
-- 
2.27.0



From jxgao at google.com  Wed Jan 27 19:38:29 2021
From: jxgao at google.com (Jianxiong Gao)
Date: Wed, 27 Jan 2021 16:38:29 -0800
Subject: [PATCH 3/3] Adding device_dma_parameters->offset_preserve_mask to
 NVMe driver.
In-Reply-To: <20210128003829.1892018-1-jxgao@google.com>
References: <20210128003829.1892018-1-jxgao@google.com>
Message-ID: <20210128003829.1892018-4-jxgao@google.com>

NVMe driver relies on the address offset to function properly.
This patch adds the offset preserve mask to NVMe driver when mapping
via dma_map_sg_attrs and unmapping via nvme_unmap_sg. The mask
depends on the page size defined by CC.MPS register of NVMe
controller.

Signed-off-by: Jianxiong Gao <jxgao at google.com>
---
 drivers/nvme/host/pci.c | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 856aa31931c1..0b23f04068be 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -580,12 +580,15 @@ static void nvme_free_sgls(struct nvme_dev *dev, struct request *req)
 static void nvme_unmap_sg(struct nvme_dev *dev, struct request *req)
 {
 	struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
-
+	if (dma_set_page_offset_mask(dev->dev, NVME_CTRL_PAGE_SIZE - 1))
+		dev_warn(dev->dev, "dma_set_page_offset_mask failed to set offset\n");
 	if (is_pci_p2pdma_page(sg_page(iod->sg)))
 		pci_p2pdma_unmap_sg(dev->dev, iod->sg, iod->nents,
 				    rq_dma_dir(req));
 	else
 		dma_unmap_sg(dev->dev, iod->sg, iod->nents, rq_dma_dir(req));
+	if (dma_set_page_offset_mask(dev->dev, 0))
+		dev_warn(dev->dev, "dma_set_page_offset_mask failed to reset offset\n");
 }
 
 static void nvme_unmap_data(struct nvme_dev *dev, struct request *req)
@@ -842,7 +845,7 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
 {
 	struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
 	blk_status_t ret = BLK_STS_RESOURCE;
-	int nr_mapped;
+	int nr_mapped, offset_ret;
 
 	if (blk_rq_nr_phys_segments(req) == 1) {
 		struct bio_vec bv = req_bvec(req);
@@ -868,12 +871,24 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
 	if (!iod->nents)
 		goto out_free_sg;
 
+	offset_ret = dma_set_page_offset_mask(dev->dev, NVME_CTRL_PAGE_SIZE - 1);
+	if (offset_ret) {
+		dev_warn(dev->dev, "dma_set_page_offset_mask failed to set offset\n");
+		goto out_free_sg;
+	}
+
 	if (is_pci_p2pdma_page(sg_page(iod->sg)))
 		nr_mapped = pci_p2pdma_map_sg_attrs(dev->dev, iod->sg,
 				iod->nents, rq_dma_dir(req), DMA_ATTR_NO_WARN);
 	else
 		nr_mapped = dma_map_sg_attrs(dev->dev, iod->sg, iod->nents,
 					     rq_dma_dir(req), DMA_ATTR_NO_WARN);
+
+	offset_ret = dma_set_page_offset_mask(dev->dev, 0);
+	if (offset_ret) {
+		dev_warn(dev->dev, "dma_set_page_offset_mask failed to reset offset\n");
+		goto out_free_sg;
+	}
 	if (!nr_mapped)
 		goto out_free_sg;
 
-- 
2.27.0



From jxgao at google.com  Wed Jan 27 19:38:28 2021
From: jxgao at google.com (Jianxiong Gao)
Date: Wed, 27 Jan 2021 16:38:28 -0800
Subject: [PATCH 2/3] Add swiotlb offset preserving mapping when
 dma_dma_parameters->page_offset_mask is non zero.
In-Reply-To: <20210128003829.1892018-1-jxgao@google.com>
References: <20210128003829.1892018-1-jxgao@google.com>
Message-ID: <20210128003829.1892018-3-jxgao@google.com>

For devices that need to preserve address offset on mapping through
swiotlb, this patch adds offset preserving based on page_offset_mask
and keeps the offset if the mask is non zero. This is needed for
device drivers like NVMe.

Signed-off-by: Jianxiong Gao <jxgao at google.com>
---
 kernel/dma/swiotlb.c | 25 ++++++++++++++++++++++---
 1 file changed, 22 insertions(+), 3 deletions(-)

diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c
index 7c42df6e6100..4cab35f2c9bc 100644
--- a/kernel/dma/swiotlb.c
+++ b/kernel/dma/swiotlb.c
@@ -468,7 +468,7 @@ phys_addr_t swiotlb_tbl_map_single(struct device *hwdev, phys_addr_t orig_addr,
 	dma_addr_t tbl_dma_addr = phys_to_dma_unencrypted(hwdev, io_tlb_start);
 	unsigned long flags;
 	phys_addr_t tlb_addr;
-	unsigned int nslots, stride, index, wrap;
+	unsigned int nslots, stride, index, wrap, page_offset_mask, page_offset;
 	int i;
 	unsigned long mask;
 	unsigned long offset_slots;
@@ -500,12 +500,16 @@ phys_addr_t swiotlb_tbl_map_single(struct device *hwdev, phys_addr_t orig_addr,
 		    ? ALIGN(mask + 1, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT
 		    : 1UL << (BITS_PER_LONG - IO_TLB_SHIFT);
 
+	page_offset_mask = dma_get_page_offset_mask(hwdev);
+	page_offset = orig_addr & page_offset_mask;
+	alloc_size += page_offset;
+
 	/*
 	 * For mappings greater than or equal to a page, we limit the stride
 	 * (and hence alignment) to a page size.
 	 */
 	nslots = ALIGN(alloc_size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
-	if (alloc_size >= PAGE_SIZE)
+	if ((alloc_size >= PAGE_SIZE) || (page_offset_mask > (1 << IO_TLB_SHIFT)))
 		stride = (1 << (PAGE_SHIFT - IO_TLB_SHIFT));
 	else
 		stride = 1;
@@ -583,6 +587,11 @@ phys_addr_t swiotlb_tbl_map_single(struct device *hwdev, phys_addr_t orig_addr,
 	 */
 	for (i = 0; i < nslots; i++)
 		io_tlb_orig_addr[index+i] = orig_addr + (i << IO_TLB_SHIFT);
+	/*
+	 * When keeping the offset of the original data, we need to advance
+	 * the tlb_addr by the offset of orig_addr.
+	 */
+	tlb_addr += page_offset;
 	if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC) &&
 	    (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL))
 		swiotlb_bounce(orig_addr, tlb_addr, mapping_size, DMA_TO_DEVICE);
@@ -598,7 +607,9 @@ void swiotlb_tbl_unmap_single(struct device *hwdev, phys_addr_t tlb_addr,
 			      enum dma_data_direction dir, unsigned long attrs)
 {
 	unsigned long flags;
-	int i, count, nslots = ALIGN(alloc_size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
+	unsigned int num_page_offset_slabs, page_offset_mask = dma_get_page_offset_mask(hwdev);
+	int i, count;
+	int nslots = ALIGN(alloc_size + tlb_addr & page_offset_mask, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
 	int index = (tlb_addr - io_tlb_start) >> IO_TLB_SHIFT;
 	phys_addr_t orig_addr = io_tlb_orig_addr[index];
 
@@ -610,6 +621,14 @@ void swiotlb_tbl_unmap_single(struct device *hwdev, phys_addr_t tlb_addr,
 	    ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL)))
 		swiotlb_bounce(orig_addr, tlb_addr, mapping_size, DMA_FROM_DEVICE);
 
+	/*
+	 * When dma_get_page_offset_mask is used, we may have padded more slabs
+	 * when padding exceeds one slab. We need to move index back to the
+	 * beginning of the padding.
+	 */
+	num_page_offset_slabs =  (tlb_addr & page_offset_mask) / (1 << IO_TLB_SHIFT);
+	index -= num_page_offset_slabs;
+
 	/*
 	 * Return the buffer to the free list by setting the corresponding
 	 * entries to indicate the number of contiguous entries available.
-- 
2.27.0



From lengchao at huawei.com  Wed Jan 27 20:31:30 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 28 Jan 2021 09:31:30 +0800
Subject: [PATCH v2] nvme-multipath: Early exit if no path is available
In-Reply-To: <20210127103033.15318-1-dwagner@suse.de>
References: <20210127103033.15318-1-dwagner@suse.de>
Message-ID: <db9baae0-547c-7ff4-8b2c-0b95f14be67c@huawei.com>



On 2021/1/27 18:30, Daniel Wagner wrote:
> nvme_round_robin_path() should test if the return ns pointer is
> valid. nvme_next_ns() will return a NULL pointer if there is no path
> left.
> 
> Fixes: 75c10e732724 ("nvme-multipath: round-robin I/O policy")
> Cc: Hannes Reinecke <hare at suse.de>
> Signed-off-by: Daniel Wagner <dwagner at suse.de>
> ---
> v2:
>    - moved NULL test into the if conditional statement
>    - added Fixes tag
> 
>   drivers/nvme/host/multipath.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
> index 9ac762b28811..282b7a4ea9a9 100644
> --- a/drivers/nvme/host/multipath.c
> +++ b/drivers/nvme/host/multipath.c
> @@ -221,7 +221,7 @@ static struct nvme_ns *nvme_round_robin_path(struct nvme_ns_head *head,
>   	}
>   
>   	for (ns = nvme_next_ns(head, old);
> -	     ns != old;
> +	     ns && ns != old;
nvme_round_robin_path just be called when !"old".
nvme_next_ns should not return NULL when !"old".
It seems unnecessary to add checking "ns".
Is there a bug that "old" in not in "head" list?
If yes, we should fix it.
>   	     ns = nvme_next_ns(head, ns)) {
>   		if (nvme_path_is_disabled(ns))
>   			continue;
> 


From lengchao at huawei.com  Wed Jan 27 20:34:27 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 28 Jan 2021 09:34:27 +0800
Subject: [PATCH v4 1/5] blk-mq: introduce blk_mq_set_request_complete
In-Reply-To: <20210127164020.GA23417@lst.de>
References: <20210126081539.13320-1-lengchao@huawei.com>
 <20210126081539.13320-2-lengchao@huawei.com> <20210127164020.GA23417@lst.de>
Message-ID: <15301bba-f7db-a0c9-c7fa-6efaafefd21c@huawei.com>



On 2021/1/28 0:40, Christoph Hellwig wrote:
>> +static inline void blk_mq_set_request_complete(struct request *rq)
>> +{
>> +	WRITE_ONCE(rq->state, MQ_RQ_COMPLETE);
>> +}
> 
> This function needs a detailed comment explaining the use case.
> Otherwise we'll get lots of driver abuses.
ok, thanks.
> .
> 


From lengchao at huawei.com  Wed Jan 27 20:36:14 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 28 Jan 2021 09:36:14 +0800
Subject: [PATCH v2] nvme-multipath: Early exit if no path is available
In-Reply-To: <20210127103033.15318-1-dwagner@suse.de>
References: <20210127103033.15318-1-dwagner@suse.de>
Message-ID: <ca8be10a-11fb-dd4d-3606-f9e75a42c99d@huawei.com>



On 2021/1/27 18:30, Daniel Wagner wrote:
> nvme_round_robin_path() should test if the return ns pointer is
> valid. nvme_next_ns() will return a NULL pointer if there is no path
> left.
> 
> Fixes: 75c10e732724 ("nvme-multipath: round-robin I/O policy")
> Cc: Hannes Reinecke <hare at suse.de>
> Signed-off-by: Daniel Wagner <dwagner at suse.de>
> ---
> v2:
>    - moved NULL test into the if conditional statement
>    - added Fixes tag
> 
>   drivers/nvme/host/multipath.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
> index 9ac762b28811..282b7a4ea9a9 100644
> --- a/drivers/nvme/host/multipath.c
> +++ b/drivers/nvme/host/multipath.c
> @@ -221,7 +221,7 @@ static struct nvme_ns *nvme_round_robin_path(struct nvme_ns_head *head,
>   	}
>   
>   	for (ns = nvme_next_ns(head, old);
> -	     ns != old;
> +	     ns && ns != old;
nvme_round_robin_path just be called when !"old".
nvme_next_ns should not return NULL when !"old".
It seems unnecessary to add checking "ns".
Is there a bug that "old" is not in "head" list?
If yes, we should fix it.
>   	     ns = nvme_next_ns(head, ns)) {
>   		if (nvme_path_is_disabled(ns))
>   			continue;
> 


From lengchao at huawei.com  Wed Jan 27 22:33:51 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 28 Jan 2021 11:33:51 +0800
Subject: [PATCH] nvme-core: use list_add_tail_rcu instead of list_add_tail for
 nvme_init_ns_head
Message-ID: <20210128033351.22116-1-lengchao@huawei.com>

The "list" of nvme_ns_head is used as rcu list, now in nvme_init_ns_head
list_add_tail is used to add ns->siblings to the rcu list. It is not safe.
Should use list_add_tail_rcu instead of list_add_tail.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 drivers/nvme/host/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 8caf9b34734d..f13eb4ded95f 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -3829,7 +3829,7 @@ static int nvme_init_ns_head(struct nvme_ns *ns, unsigned nsid,
 		}
 	}
 
-	list_add_tail(&ns->siblings, &head->list);
+	list_add_tail_rcu(&ns->siblings, &head->list);
 	ns->head = head;
 	mutex_unlock(&ctrl->subsys->lock);
 	return 0;
-- 
2.16.4



From damien.lemoal at wdc.com  Wed Jan 27 23:47:26 2021
From: damien.lemoal at wdc.com (Damien Le Moal)
Date: Thu, 28 Jan 2021 13:47:26 +0900
Subject: [PATCH v4 1/8] block: document zone_append_max_bytes attribute
In-Reply-To: <20210128044733.503606-1-damien.lemoal@wdc.com>
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
Message-ID: <20210128044733.503606-2-damien.lemoal@wdc.com>

The description of the zone_append_max_bytes sysfs queue attribute is
missing from Documentation/block/queue-sysfs.rst. Add it.

Signed-off-by: Damien Le Moal <damien.lemoal at wdc.com>
Reviewed-by: Christoph Hellwig <hch at lst.de>
Reviewed-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
Reviewed-by: Martin K. Petersen <martin.petersen at oracle.com>
---
 Documentation/block/queue-sysfs.rst | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/block/queue-sysfs.rst b/Documentation/block/queue-sysfs.rst
index 2638d3446b79..edc6e6960b96 100644
--- a/Documentation/block/queue-sysfs.rst
+++ b/Documentation/block/queue-sysfs.rst
@@ -261,6 +261,12 @@ For block drivers that support REQ_OP_WRITE_ZEROES, the maximum number of
 bytes that can be zeroed at once. The value 0 means that REQ_OP_WRITE_ZEROES
 is not supported.
 
+zone_append_max_bytes (RO)
+--------------------------
+This is the maximum number of bytes that can be written to a sequential
+zone of a zoned block device using a zone append write operation
+(REQ_OP_ZONE_APPEND). This value is always 0 for regular block devices.
+
 zoned (RO)
 ----------
 This indicates if the device is a zoned block device and the zone model of the
-- 
2.29.2



From damien.lemoal at wdc.com  Wed Jan 27 23:47:25 2021
From: damien.lemoal at wdc.com (Damien Le Moal)
Date: Thu, 28 Jan 2021 13:47:25 +0900
Subject: [PATCH v4 0/8] block: add zone write granularity limit
Message-ID: <20210128044733.503606-1-damien.lemoal@wdc.com>

The first patch of this series adds missing documentation of the
zone_append_max_bytes sysfs attribute.

The following 3 patches are cleanup and preparatory patches for the
introduction of the zone write granularity limit. The goal of these
patches is to have all code setting a device queue zoned model to use
the helper function blk_queue_set_zoned(). The nvme driver, null_blk
driver and the partition code are modified to do so.

The fourth patch in this series introduces the zone write granularity
queue limit to indicate the alignment constraint for write operations
into sequential zones of zoned block devices. This limit is always set
by default to the device logical block size. The following patch
documents this new limit.

The last 2 patches introduce the blk_queue_clear_zone_settings()
function and modify the SCSI sd driver to clear the zone related queue
limits and resources of a host-aware zoned disk that is changed to a
regular disk due to the presence of partitions.

Changes from v3:
* Added pathces 2, 3, 4, 7 and 8
* Addressed Christoph's comments on patch 5

Changes from v2:
* Added patch 3 for zonefs
* Addressed Christoph's comments on patch 1 and added the limit
  initialization for zoned nullblk

Changes from v1:
* Fixed typo in patch 2

Damien Le Moal (8):
  block: document zone_append_max_bytes attribute
  nvme: cleanup zone information initialization
  nullb: use blk_queue_set_zoned() to setup zoned devices
  block: use blk_queue_set_zoned in add_partition()
  block: introduce zone_write_granularity limit
  zonefs: use zone write granularity as block size
  block: introduce blk_queue_clear_zone_settings()
  sd_zbc: clear zone resources for non-zoned case

Damien Le Moal (8):
  block: document zone_append_max_bytes attribute
  nvme: cleanup zone information initialization
  nullb: use blk_queue_set_zoned() to setup zoned devices
  block: use blk_queue_set_zoned in add_partition()
  block: introduce zone_write_granularity limit
  zonefs: use zone write granularity as block size
  block: introduce blk_queue_clear_zone_settings()
  sd_zbc: clear zone resources for non-zoned case

 Documentation/block/queue-sysfs.rst | 13 +++++++++
 block/blk-settings.c                | 39 +++++++++++++++++++++++++-
 block/blk-sysfs.c                   |  8 ++++++
 block/blk-zoned.c                   | 17 ++++++++++++
 block/blk.h                         |  2 ++
 block/partitions/core.c             |  2 +-
 drivers/block/null_blk/zoned.c      |  8 +++---
 drivers/nvme/host/core.c            | 11 ++++----
 drivers/nvme/host/zns.c             | 11 ++------
 drivers/scsi/sd_zbc.c               | 43 ++++++++++++++++++++++++++---
 fs/zonefs/super.c                   |  9 +++---
 include/linux/blkdev.h              | 15 ++++++++++
 12 files changed, 150 insertions(+), 28 deletions(-)

-- 
2.29.2



From damien.lemoal at wdc.com  Wed Jan 27 23:47:27 2021
From: damien.lemoal at wdc.com (Damien Le Moal)
Date: Thu, 28 Jan 2021 13:47:27 +0900
Subject: [PATCH v4 2/8] nvme: cleanup zone information initialization
In-Reply-To: <20210128044733.503606-1-damien.lemoal@wdc.com>
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
Message-ID: <20210128044733.503606-3-damien.lemoal@wdc.com>

For a zoned namespace, in nvme_update_ns_info(), call
nvme_update_zone_info() after executing nvme_update_disk_info() so that
the namespace queue logical and physical block size limits are set.
This allows setting the namespace queue max_zone_append_sectors limit
in nvme_update_zone_info() instead of nvme_revalidate_zones(),
simplifying this function. Also use blk_queue_set_zoned() to set the
namespace zoned model.

Signed-off-by: Damien Le Moal <damien.lemoal at wdc.com>
---
 drivers/nvme/host/core.c | 11 ++++++-----
 drivers/nvme/host/zns.c  | 11 +++--------
 2 files changed, 9 insertions(+), 13 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 1a3cdc6b1036..81a1c7f6223f 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -2176,17 +2176,18 @@ static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_id_ns *id)
 	ns->lba_shift = id->lbaf[lbaf].ds;
 	nvme_set_queue_limits(ns->ctrl, ns->queue);
 
+	ret = nvme_configure_metadata(ns, id);
+	if (ret)
+		goto out_unfreeze;
+	nvme_set_chunk_sectors(ns, id);
+	nvme_update_disk_info(ns->disk, ns, id);
+
 	if (ns->head->ids.csi == NVME_CSI_ZNS) {
 		ret = nvme_update_zone_info(ns, lbaf);
 		if (ret)
 			goto out_unfreeze;
 	}
 
-	ret = nvme_configure_metadata(ns, id);
-	if (ret)
-		goto out_unfreeze;
-	nvme_set_chunk_sectors(ns, id);
-	nvme_update_disk_info(ns->disk, ns, id);
 	blk_mq_unfreeze_queue(ns->disk->queue);
 
 	if (blk_queue_is_zoned(ns->queue)) {
diff --git a/drivers/nvme/host/zns.c b/drivers/nvme/host/zns.c
index 1dfe9a3500e3..c7e3ec561ba0 100644
--- a/drivers/nvme/host/zns.c
+++ b/drivers/nvme/host/zns.c
@@ -9,13 +9,7 @@
 
 int nvme_revalidate_zones(struct nvme_ns *ns)
 {
-	struct request_queue *q = ns->queue;
-	int ret;
-
-	ret = blk_revalidate_disk_zones(ns->disk, NULL);
-	if (!ret)
-		blk_queue_max_zone_append_sectors(q, ns->ctrl->max_zone_append);
-	return ret;
+	return blk_revalidate_disk_zones(ns->disk, NULL);
 }
 
 static int nvme_set_max_append(struct nvme_ctrl *ctrl)
@@ -109,10 +103,11 @@ int nvme_update_zone_info(struct nvme_ns *ns, unsigned lbaf)
 		goto free_data;
 	}
 
-	q->limits.zoned = BLK_ZONED_HM;
+	blk_queue_set_zoned(ns->disk, BLK_ZONED_HM);
 	blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, q);
 	blk_queue_max_open_zones(q, le32_to_cpu(id->mor) + 1);
 	blk_queue_max_active_zones(q, le32_to_cpu(id->mar) + 1);
+	blk_queue_max_zone_append_sectors(q, ns->ctrl->max_zone_append);
 free_data:
 	kfree(id);
 	return status;
-- 
2.29.2



From damien.lemoal at wdc.com  Wed Jan 27 23:47:28 2021
From: damien.lemoal at wdc.com (Damien Le Moal)
Date: Thu, 28 Jan 2021 13:47:28 +0900
Subject: [PATCH v4 3/8] nullb: use blk_queue_set_zoned() to setup zoned devices
In-Reply-To: <20210128044733.503606-1-damien.lemoal@wdc.com>
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
Message-ID: <20210128044733.503606-4-damien.lemoal@wdc.com>

Use blk_queue_set_zoned() to set a nullb device zone model instead of
directly assigning the device queue zoned limit. This initialization of
the devicve zoned model as well as the setup of the queue flag
QUEUE_FLAG_ZONE_RESETALL and of the device queue elevator feature are
moved from null_init_zoned_dev() to null_register_zoned_dev() so that
the initialization of the queue limits is done when the gendisk of the
nullb device is available.

Signed-off-by: Damien Le Moal <damien.lemoal at wdc.com>
---
 drivers/block/null_blk/zoned.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/block/null_blk/zoned.c b/drivers/block/null_blk/zoned.c
index 148b871f263b..78cae8703dcf 100644
--- a/drivers/block/null_blk/zoned.c
+++ b/drivers/block/null_blk/zoned.c
@@ -146,10 +146,6 @@ int null_init_zoned_dev(struct nullb_device *dev, struct request_queue *q)
 		sector += dev->zone_size_sects;
 	}
 
-	q->limits.zoned = BLK_ZONED_HM;
-	blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, q);
-	blk_queue_required_elevator_features(q, ELEVATOR_F_ZBD_SEQ_WRITE);
-
 	return 0;
 }
 
@@ -158,6 +154,10 @@ int null_register_zoned_dev(struct nullb *nullb)
 	struct nullb_device *dev = nullb->dev;
 	struct request_queue *q = nullb->q;
 
+	blk_queue_set_zoned(nullb->disk, BLK_ZONED_HM);
+	blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, q);
+	blk_queue_required_elevator_features(q, ELEVATOR_F_ZBD_SEQ_WRITE);
+
 	if (queue_is_mq(q)) {
 		int ret = blk_revalidate_disk_zones(nullb->disk, NULL);
 
-- 
2.29.2



From damien.lemoal at wdc.com  Wed Jan 27 23:47:29 2021
From: damien.lemoal at wdc.com (Damien Le Moal)
Date: Thu, 28 Jan 2021 13:47:29 +0900
Subject: [PATCH v4 4/8] block: use blk_queue_set_zoned in add_partition()
In-Reply-To: <20210128044733.503606-1-damien.lemoal@wdc.com>
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
Message-ID: <20210128044733.503606-5-damien.lemoal@wdc.com>

When changing the zoned model of host-aware zoned block devices, use
blk_queue_set_zoned() instead of directly assigning the gendisk queue
zoned limit.

Signed-off-by: Damien Le Moal <damien.lemoal at wdc.com>
---
 block/partitions/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/block/partitions/core.c b/block/partitions/core.c
index b1cdf88f96e2..d6094203116a 100644
--- a/block/partitions/core.c
+++ b/block/partitions/core.c
@@ -334,7 +334,7 @@ static struct block_device *add_partition(struct gendisk *disk, int partno,
 	case BLK_ZONED_HA:
 		pr_info("%s: disabling host aware zoned block device support due to partitions\n",
 			disk->disk_name);
-		disk->queue->limits.zoned = BLK_ZONED_NONE;
+		blk_queue_set_zoned(disk, BLK_ZONED_NONE);
 		break;
 	case BLK_ZONED_NONE:
 		break;
-- 
2.29.2



From damien.lemoal at wdc.com  Wed Jan 27 23:47:30 2021
From: damien.lemoal at wdc.com (Damien Le Moal)
Date: Thu, 28 Jan 2021 13:47:30 +0900
Subject: [PATCH v4 5/8] block: introduce zone_write_granularity limit
In-Reply-To: <20210128044733.503606-1-damien.lemoal@wdc.com>
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
Message-ID: <20210128044733.503606-6-damien.lemoal@wdc.com>

Per ZBC and ZAC specifications, host-managed SMR hard-disks mandate that
all writes into sequential write required zones be aligned to the device
physical block size. However, NVMe ZNS does not have this constraint and
allows write operations into sequential zones to be aligned to the
device logical block size. This inconsistency does not help with
software portability across device types.

To solve this, introduce the zone_write_granularity queue limit to
indicate the alignment constraint, in bytes, of write operations into
zones of a zoned block device. This new limit is exported as a
read-only sysfs queue attribute and the helper
blk_queue_zone_write_granularity() introduced for drivers to set this
limit.

The function blk_queue_set_zoned() is modified to set this new limit to
the device logical block size by default. NVMe ZNS devices as well as
zoned nullb devices use this default value as is. The scsi disk driver
is modified to execute the blk_queue_zone_write_granularity() helper to
set the zone write granularity of host-managed SMR disks to the disk
physical block size.

The accessor functions queue_zone_write_granularity() and
bdev_zone_write_granularity() are also introduced.

Signed-off-by: Damien Le Moal <damien.lemoal at wdc.com>
---
 Documentation/block/queue-sysfs.rst |  7 ++++++
 block/blk-settings.c                | 37 ++++++++++++++++++++++++++++-
 block/blk-sysfs.c                   |  8 +++++++
 drivers/scsi/sd_zbc.c               |  8 +++++++
 include/linux/blkdev.h              | 15 ++++++++++++
 5 files changed, 74 insertions(+), 1 deletion(-)

diff --git a/Documentation/block/queue-sysfs.rst b/Documentation/block/queue-sysfs.rst
index edc6e6960b96..4dc7f0d499a8 100644
--- a/Documentation/block/queue-sysfs.rst
+++ b/Documentation/block/queue-sysfs.rst
@@ -279,4 +279,11 @@ devices are described in the ZBC (Zoned Block Commands) and ZAC
 do not support zone commands, they will be treated as regular block devices
 and zoned will report "none".
 
+zone_write_granularity (RO)
+---------------------------
+This indicates the alignment constraint, in bytes, for write operations in
+sequential zones of zoned block devices (devices with a zoned attributed
+that reports "host-managed" or "host-aware"). This value is always 0 for
+regular block devices.
+
 Jens Axboe <jens.axboe at oracle.com>, February 2009
diff --git a/block/blk-settings.c b/block/blk-settings.c
index 4c974340f1a9..a1e66165adcf 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -60,6 +60,7 @@ void blk_set_default_limits(struct queue_limits *lim)
 	lim->io_opt = 0;
 	lim->misaligned = 0;
 	lim->zoned = BLK_ZONED_NONE;
+	lim->zone_write_granularity = 0;
 }
 EXPORT_SYMBOL(blk_set_default_limits);
 
@@ -366,6 +367,28 @@ void blk_queue_physical_block_size(struct request_queue *q, unsigned int size)
 }
 EXPORT_SYMBOL(blk_queue_physical_block_size);
 
+/**
+ * blk_queue_zone_write_granularity - set zone write granularity for the queue
+ * @q:  the request queue for the zoned device
+ * @size:  the zone write granularity size, in bytes
+ *
+ * Description:
+ *   This should be set to the lowest possible size allowing to write in
+ *   sequential zones of a zoned block device.
+ */
+void blk_queue_zone_write_granularity(struct request_queue *q,
+				      unsigned int size)
+{
+	if (WARN_ON_ONCE(!blk_queue_is_zoned(q)))
+		return;
+
+	q->limits.zone_write_granularity = size;
+
+	if (q->limits.zone_write_granularity < q->limits.logical_block_size)
+		q->limits.zone_write_granularity = q->limits.logical_block_size;
+}
+EXPORT_SYMBOL_GPL(blk_queue_zone_write_granularity);
+
 /**
  * blk_queue_alignment_offset - set physical block alignment offset
  * @q:	the request queue for the device
@@ -631,6 +654,8 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
 			t->discard_granularity;
 	}
 
+	t->zone_write_granularity = max(t->zone_write_granularity,
+					b->zone_write_granularity);
 	t->zoned = max(t->zoned, b->zoned);
 	return ret;
 }
@@ -847,6 +872,8 @@ EXPORT_SYMBOL_GPL(blk_queue_can_use_dma_map_merging);
  */
 void blk_queue_set_zoned(struct gendisk *disk, enum blk_zoned_model model)
 {
+	struct request_queue *q = disk->queue;
+
 	switch (model) {
 	case BLK_ZONED_HM:
 		/*
@@ -875,7 +902,15 @@ void blk_queue_set_zoned(struct gendisk *disk, enum blk_zoned_model model)
 		break;
 	}
 
-	disk->queue->limits.zoned = model;
+	q->limits.zoned = model;
+	if (model != BLK_ZONED_NONE) {
+		/*
+		 * Set the zone write granularity to the device logical block
+		 * size by default. The driver can change this value if needed.
+		 */
+		blk_queue_zone_write_granularity(q,
+						queue_logical_block_size(q));
+	}
 }
 EXPORT_SYMBOL_GPL(blk_queue_set_zoned);
 
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index b513f1683af0..ae39c7f3d83d 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -219,6 +219,12 @@ static ssize_t queue_write_zeroes_max_show(struct request_queue *q, char *page)
 		(unsigned long long)q->limits.max_write_zeroes_sectors << 9);
 }
 
+static ssize_t queue_zone_write_granularity_show(struct request_queue *q,
+						 char *page)
+{
+	return queue_var_show(queue_zone_write_granularity(q), page);
+}
+
 static ssize_t queue_zone_append_max_show(struct request_queue *q, char *page)
 {
 	unsigned long long max_sectors = q->limits.max_zone_append_sectors;
@@ -585,6 +591,7 @@ QUEUE_RO_ENTRY(queue_discard_zeroes_data, "discard_zeroes_data");
 QUEUE_RO_ENTRY(queue_write_same_max, "write_same_max_bytes");
 QUEUE_RO_ENTRY(queue_write_zeroes_max, "write_zeroes_max_bytes");
 QUEUE_RO_ENTRY(queue_zone_append_max, "zone_append_max_bytes");
+QUEUE_RO_ENTRY(queue_zone_write_granularity, "zone_write_granularity");
 
 QUEUE_RO_ENTRY(queue_zoned, "zoned");
 QUEUE_RO_ENTRY(queue_nr_zones, "nr_zones");
@@ -639,6 +646,7 @@ static struct attribute *queue_attrs[] = {
 	&queue_write_same_max_entry.attr,
 	&queue_write_zeroes_max_entry.attr,
 	&queue_zone_append_max_entry.attr,
+	&queue_zone_write_granularity_entry.attr,
 	&queue_nonrot_entry.attr,
 	&queue_zoned_entry.attr,
 	&queue_nr_zones_entry.attr,
diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c
index cf07b7f93579..8293b29584b3 100644
--- a/drivers/scsi/sd_zbc.c
+++ b/drivers/scsi/sd_zbc.c
@@ -789,6 +789,14 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf)
 	blk_queue_max_active_zones(q, 0);
 	nr_zones = round_up(sdkp->capacity, zone_blocks) >> ilog2(zone_blocks);
 
+	/*
+	 * Per ZBC and ZAC specifications, writes in sequential write required
+	 * zones of host-managed devices must be aligned to the device physical
+	 * block size.
+	 */
+	if (blk_queue_zoned_model(q) == BLK_ZONED_HM)
+		blk_queue_zone_write_granularity(q, sdkp->physical_block_size);
+
 	/* READ16/WRITE16 is mandatory for ZBC disks */
 	sdkp->device->use_16_for_rw = 1;
 	sdkp->device->use_10_for_rw = 0;
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 0dea268bd61b..9149f4a5adb3 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -337,6 +337,7 @@ struct queue_limits {
 	unsigned int		max_zone_append_sectors;
 	unsigned int		discard_granularity;
 	unsigned int		discard_alignment;
+	unsigned int		zone_write_granularity;
 
 	unsigned short		max_segments;
 	unsigned short		max_integrity_segments;
@@ -1160,6 +1161,8 @@ extern void blk_queue_logical_block_size(struct request_queue *, unsigned int);
 extern void blk_queue_max_zone_append_sectors(struct request_queue *q,
 		unsigned int max_zone_append_sectors);
 extern void blk_queue_physical_block_size(struct request_queue *, unsigned int);
+void blk_queue_zone_write_granularity(struct request_queue *q,
+				      unsigned int size);
 extern void blk_queue_alignment_offset(struct request_queue *q,
 				       unsigned int alignment);
 void blk_queue_update_readahead(struct request_queue *q);
@@ -1473,6 +1476,18 @@ static inline int bdev_io_opt(struct block_device *bdev)
 	return queue_io_opt(bdev_get_queue(bdev));
 }
 
+static inline unsigned int
+queue_zone_write_granularity(const struct request_queue *q)
+{
+	return q->limits.zone_write_granularity;
+}
+
+static inline unsigned int
+bdev_zone_write_granularity(struct block_device *bdev)
+{
+	return queue_zone_write_granularity(bdev_get_queue(bdev));
+}
+
 static inline int queue_alignment_offset(const struct request_queue *q)
 {
 	if (q->limits.misaligned)
-- 
2.29.2



From damien.lemoal at wdc.com  Wed Jan 27 23:47:31 2021
From: damien.lemoal at wdc.com (Damien Le Moal)
Date: Thu, 28 Jan 2021 13:47:31 +0900
Subject: [PATCH v4 6/8] zonefs: use zone write granularity as block size
In-Reply-To: <20210128044733.503606-1-damien.lemoal@wdc.com>
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
Message-ID: <20210128044733.503606-7-damien.lemoal@wdc.com>

Zoned block devices have different granularity constraints for write
operations into sequential zones. E.g. ZBC and ZAC devices require that
writes be aligned to the device physical block size while NVMe ZNS
devices allow logical block size aligned write operations. To correctly
handle such difference, use the device zone write granularity limit to
set the block size of a zonefs volume, thus allowing the smallest
possible write unit for all zoned device types.

Signed-off-by: Damien Le Moal <damien.lemoal at wdc.com>
Reviewed-by: Christoph Hellwig <hch at lst.de>
Reviewed-by: Martin K. Petersen <martin.petersen at oracle.com>
---
 fs/zonefs/super.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/fs/zonefs/super.c b/fs/zonefs/super.c
index ab68e27bb322..b9fb55b250ae 100644
--- a/fs/zonefs/super.c
+++ b/fs/zonefs/super.c
@@ -1581,12 +1581,11 @@ static int zonefs_fill_super(struct super_block *sb, void *data, int silent)
 	sb->s_time_gran	= 1;
 
 	/*
-	 * The block size is set to the device physical sector size to ensure
-	 * that write operations on 512e devices (512B logical block and 4KB
-	 * physical block) are always aligned to the device physical blocks,
-	 * as mandated by the ZBC/ZAC specifications.
+	 * The block size is set to the device zone write granularity to ensure
+	 * that write operations are always aligned according to the device
+	 * interface constraints.
 	 */
-	sb_set_blocksize(sb, bdev_physical_block_size(sb->s_bdev));
+	sb_set_blocksize(sb, bdev_zone_write_granularity(sb->s_bdev));
 	sbi->s_zone_sectors_shift = ilog2(bdev_zone_sectors(sb->s_bdev));
 	sbi->s_uid = GLOBAL_ROOT_UID;
 	sbi->s_gid = GLOBAL_ROOT_GID;
-- 
2.29.2



From damien.lemoal at wdc.com  Wed Jan 27 23:47:32 2021
From: damien.lemoal at wdc.com (Damien Le Moal)
Date: Thu, 28 Jan 2021 13:47:32 +0900
Subject: [PATCH v4 7/8] block: introduce blk_queue_clear_zone_settings()
In-Reply-To: <20210128044733.503606-1-damien.lemoal@wdc.com>
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
Message-ID: <20210128044733.503606-8-damien.lemoal@wdc.com>

Introduce the internal function blk_queue_clear_zone_settings() to
cleanup all limits and resources related to zoned block devices. This
new function is called from blk_queue_set_zoned() when a disk zoned
model is set to BLK_ZONED_NONE. This particular case can happens when a
partition is created on a host-aware scsi disk.

Signed-off-by: Damien Le Moal <damien.lemoal at wdc.com>
---
 block/blk-settings.c |  2 ++
 block/blk-zoned.c    | 17 +++++++++++++++++
 block/blk.h          |  2 ++
 3 files changed, 21 insertions(+)

diff --git a/block/blk-settings.c b/block/blk-settings.c
index a1e66165adcf..7dd8be314ac6 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -910,6 +910,8 @@ void blk_queue_set_zoned(struct gendisk *disk, enum blk_zoned_model model)
 		 */
 		blk_queue_zone_write_granularity(q,
 						queue_logical_block_size(q));
+	} else {
+		blk_queue_clear_zone_settings(q);
 	}
 }
 EXPORT_SYMBOL_GPL(blk_queue_set_zoned);
diff --git a/block/blk-zoned.c b/block/blk-zoned.c
index 7a68b6e4300c..833978c02e60 100644
--- a/block/blk-zoned.c
+++ b/block/blk-zoned.c
@@ -549,3 +549,20 @@ int blk_revalidate_disk_zones(struct gendisk *disk,
 	return ret;
 }
 EXPORT_SYMBOL_GPL(blk_revalidate_disk_zones);
+
+void blk_queue_clear_zone_settings(struct request_queue *q)
+{
+	blk_mq_freeze_queue(q);
+
+	blk_queue_free_zone_bitmaps(q);
+	blk_queue_flag_clear(QUEUE_FLAG_ZONE_RESETALL, q);
+	q->required_elevator_features &= ~ELEVATOR_F_ZBD_SEQ_WRITE;
+	q->nr_zones = 0;
+	q->max_open_zones = 0;
+	q->max_active_zones = 0;
+	q->limits.chunk_sectors = 0;
+	q->limits.zone_write_granularity = 0;
+	q->limits.max_zone_append_sectors = 0;
+
+	blk_mq_unfreeze_queue(q);
+}
diff --git a/block/blk.h b/block/blk.h
index 0198335c5838..977d79a0d99a 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -333,8 +333,10 @@ struct bio *blk_next_bio(struct bio *bio, unsigned int nr_pages, gfp_t gfp);
 
 #ifdef CONFIG_BLK_DEV_ZONED
 void blk_queue_free_zone_bitmaps(struct request_queue *q);
+void blk_queue_clear_zone_settings(struct request_queue *q);
 #else
 static inline void blk_queue_free_zone_bitmaps(struct request_queue *q) {}
+static inline void blk_queue_clear_zone_settings(struct request_queue *q) {}
 #endif
 
 int blk_alloc_devt(struct block_device *part, dev_t *devt);
-- 
2.29.2



From damien.lemoal at wdc.com  Wed Jan 27 23:47:33 2021
From: damien.lemoal at wdc.com (Damien Le Moal)
Date: Thu, 28 Jan 2021 13:47:33 +0900
Subject: [PATCH v4 8/8] sd_zbc: clear zone resources for non-zoned case
In-Reply-To: <20210128044733.503606-1-damien.lemoal@wdc.com>
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
Message-ID: <20210128044733.503606-9-damien.lemoal@wdc.com>

For host-aware ZBC disk, setting the device zoned model to BLK_ZONED_HA
using blk_queue_set_zoned() in sd_read_block_characteristics() may
result in the block device effective zoned model to be "none"
(BLK_ZONED_NONE) if partitions are present on the device. In this case,
sd_zbc_read_zones() should not setup the zone related queue limits for
the disk so that the device limits and configuration is consistent with
a regular disk and resources not uselessly allocated (e.g. the zone
write pointer tracking array for zone append emulation).

Furthermore, if the disk zoned model changes at run time due to the
creation of a partition by the user, the zone related resources can be
released.

Fix both problems by introducing the function sd_zbc_clear_zone_info()
to reset the scsi disk zone information and free resources and by
returning early in sd_zbc_read_zones() for a block device that has a
zoned model equal to BLK_ZONED_NONE.

Signed-off-by: Damien Le Moal <damien.lemoal at wdc.com>
---
 drivers/scsi/sd_zbc.c | 37 ++++++++++++++++++++++++++++++++-----
 1 file changed, 32 insertions(+), 5 deletions(-)

diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c
index 8293b29584b3..03adb39293c2 100644
--- a/drivers/scsi/sd_zbc.c
+++ b/drivers/scsi/sd_zbc.c
@@ -665,12 +665,28 @@ static int sd_zbc_init_disk(struct scsi_disk *sdkp)
 	return 0;
 }
 
-void sd_zbc_release_disk(struct scsi_disk *sdkp)
+static void sd_zbc_clear_zone_info(struct scsi_disk *sdkp)
 {
+	/* Serialize against revalidate zones */
+	mutex_lock(&sdkp->rev_mutex);
+
 	kvfree(sdkp->zones_wp_offset);
 	sdkp->zones_wp_offset = NULL;
 	kfree(sdkp->zone_wp_update_buf);
 	sdkp->zone_wp_update_buf = NULL;
+
+	sdkp->nr_zones = 0;
+	sdkp->rev_nr_zones = 0;
+	sdkp->zone_blocks = 0;
+	sdkp->rev_zone_blocks = 0;
+
+	mutex_unlock(&sdkp->rev_mutex);
+}
+
+void sd_zbc_release_disk(struct scsi_disk *sdkp)
+{
+	if (sd_is_zoned(sdkp))
+		sd_zbc_clear_zone_info(sdkp);
 }
 
 static void sd_zbc_revalidate_zones_cb(struct gendisk *disk)
@@ -769,6 +785,21 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf)
 		 */
 		return 0;
 
+	/* READ16/WRITE16 is mandatory for ZBC disks */
+	sdkp->device->use_16_for_rw = 1;
+	sdkp->device->use_10_for_rw = 0;
+
+	if (!blk_queue_is_zoned(q)) {
+		/*
+		 * This can happen for a host aware disk with partitions.
+		 * The block device zone information was already cleared
+		 * by blk_queue_set_zoned(). Only clear the scsi disk zone
+		 * information and exit early.
+		 */
+		sd_zbc_clear_zone_info(sdkp);
+		return 0;
+	}
+
 	/* Check zoned block device characteristics (unconstrained reads) */
 	ret = sd_zbc_check_zoned_characteristics(sdkp, buf);
 	if (ret)
@@ -797,10 +828,6 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf)
 	if (blk_queue_zoned_model(q) == BLK_ZONED_HM)
 		blk_queue_zone_write_granularity(q, sdkp->physical_block_size);
 
-	/* READ16/WRITE16 is mandatory for ZBC disks */
-	sdkp->device->use_16_for_rw = 1;
-	sdkp->device->use_10_for_rw = 0;
-
 	sdkp->rev_nr_zones = nr_zones;
 	sdkp->rev_zone_blocks = zone_blocks;
 
-- 
2.29.2



From Chaitanya.Kulkarni at wdc.com  Thu Jan 28 00:12:06 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Thu, 28 Jan 2021 05:12:06 +0000
Subject: [PATCH v4 3/8] nullb: use blk_queue_set_zoned() to setup zoned
 devices
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
 <20210128044733.503606-4-damien.lemoal@wdc.com>
Message-ID: <BYAPR04MB496523B7A0DFEB865B89EE0686BA9@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/27/21 20:47, Damien Le Moal wrote:
> Use blk_queue_set_zoned() to set a nullb device zone model instead of
> directly assigning the device queue zoned limit. This initialization of
> the devicve zoned model as well as the setup of the queue flag
> QUEUE_FLAG_ZONE_RESETALL and of the device queue elevator feature are
> moved from null_init_zoned_dev() to null_register_zoned_dev() so that
> the initialization of the queue limits is done when the gendisk of the
> nullb device is available.
>
> Signed-off-by: Damien Le Moal <damien.lemoal at wdc.com>
Looks good.

Reviewed-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>



From Chaitanya.Kulkarni at wdc.com  Thu Jan 28 00:16:15 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Thu, 28 Jan 2021 05:16:15 +0000
Subject: [PATCH v4 4/8] block: use blk_queue_set_zoned in add_partition()
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
 <20210128044733.503606-5-damien.lemoal@wdc.com>
Message-ID: <BYAPR04MB4965A5326735FC0DDF3BAA9E86BA9@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/27/21 20:47, Damien Le Moal wrote:
> When changing the zoned model of host-aware zoned block devices, use
> blk_queue_set_zoned() instead of directly assigning the gendisk queue
> zoned limit.
>
> Signed-off-by: Damien Le Moal <damien.lemoal at wdc.com>
Looks good.

Reviewed-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>



From Chaitanya.Kulkarni at wdc.com  Thu Jan 28 00:17:24 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Thu, 28 Jan 2021 05:17:24 +0000
Subject: [PATCH v4 6/8] zonefs: use zone write granularity as block size
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
 <20210128044733.503606-7-damien.lemoal@wdc.com>
Message-ID: <BYAPR04MB4965377962784FD8065FAF9886BA9@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/27/21 20:47, Damien Le Moal wrote:
> Zoned block devices have different granularity constraints for write
> operations into sequential zones. E.g. ZBC and ZAC devices require that
> writes be aligned to the device physical block size while NVMe ZNS
> devices allow logical block size aligned write operations. To correctly
> handle such difference, use the device zone write granularity limit to
> set the block size of a zonefs volume, thus allowing the smallest
> possible write unit for all zoned device types.
>
> Signed-off-by: Damien Le Moal <damien.lemoal at wdc.com>
> Reviewed-by: Christoph Hellwig <hch at lst.de>
> Reviewed-by: Martin K. Petersen <martin.petersen at oracle.com>
Looks good.

Reviewed-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>



From Chaitanya.Kulkarni at wdc.com  Thu Jan 28 00:26:09 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Thu, 28 Jan 2021 05:26:09 +0000
Subject: [PATCH v4 7/8] block: introduce blk_queue_clear_zone_settings()
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
 <20210128044733.503606-8-damien.lemoal@wdc.com>
Message-ID: <BYAPR04MB496527AB027FB7BF084FEF9186BA9@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/27/21 20:47, Damien Le Moal wrote:
> Introduce the internal function blk_queue_clear_zone_settings() to
> cleanup all limits and resources related to zoned block devices. This
> new function is called from blk_queue_set_zoned() when a disk zoned
> model is set to BLK_ZONED_NONE. This particular case can happens when a
> partition is created on a host-aware scsi disk.
>
> Signed-off-by: Damien Le Moal <damien.lemoal at wdc.com>
nit:- can be done at the time of applying the patch.
In the last line of the commit log :-

1. s/happens/happen/.
2. article 'a' on the same line with the noun 'partition'.

see it make sense otherwise ignore :-

Introduce the internal function blk_queue_clear_zone_settings() to
cleanup all limits and resources related to zoned block devices. This
new function is called from blk_queue_set_zoned() when a disk zoned
model is set to BLK_ZONED_NONE. This particular case can happen when
apartition is created on a host-aware scsi disk.

Either case LGTM,

Reviewed-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>



From Chaitanya.Kulkarni at wdc.com  Thu Jan 28 00:38:55 2021
From: Chaitanya.Kulkarni at wdc.com (Chaitanya Kulkarni)
Date: Thu, 28 Jan 2021 05:38:55 +0000
Subject: [PATCH v4 8/8] sd_zbc: clear zone resources for non-zoned case
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
 <20210128044733.503606-9-damien.lemoal@wdc.com>
Message-ID: <BYAPR04MB49655B5B6075B83CEFE57C6D86BA9@BYAPR04MB4965.namprd04.prod.outlook.com>

On 1/27/21 20:47, Damien Le Moal wrote:
> -void sd_zbc_release_disk(struct scsi_disk *sdkp)
> +static void sd_zbc_clear_zone_info(struct scsi_disk *sdkp)
>  {
> +	/* Serialize against revalidate zones */
> +	mutex_lock(&sdkp->rev_mutex);
> +
>  	kvfree(sdkp->zones_wp_offset);
>  	sdkp->zones_wp_offset = NULL;
>  	kfree(sdkp->zone_wp_update_buf);
>  	sdkp->zone_wp_update_buf = NULL;
> +
> +	sdkp->nr_zones = 0;
> +	sdkp->rev_nr_zones = 0;
> +	sdkp->zone_blocks = 0;
> +	sdkp->rev_zone_blocks = 0;
> +
> +	mutex_unlock(&sdkp->rev_mutex);
> +}
> +
> +void sd_zbc_release_disk(struct scsi_disk *sdkp)
> +{
> +	if (sd_is_zoned(sdkp))
> +		sd_zbc_clear_zone_info(sdkp);
>  }
>  
If I'm not wrong there is only one caller for sd_zbc_clear_zone_info().
Is there any reason why sd_zbc_clear_zone_info() is notopen coded with
a meaningful comment in sd_zbc_release_disk() ? e.g. :-

void sd_zbc_release_disk(struct scsi_disk *sdkp)
{
	if (!sd_is_zoned(sdkp))
		return; 
	/* Serialize against revalidate zones */
	mutex_lock(&sdkp->rev_mutex);

 	kvfree(sdkp->zones_wp_offset);
 	sdkp->zones_wp_offset = NULL;
 	kfree(sdkp->zone_wp_update_buf);
 	sdkp->zone_wp_update_buf = NULL;

	/* clear zone info */
	sdkp->nr_zones = 0;
	sdkp->rev_nr_zones = 0;
	sdkp->zone_blocks = 0;
	sdkp->rev_zone_blocks = 0;

	mutex_unlock(&sdkp->rev_mutex);
 }


unless I miss something, in either case LGTM.

Reviewed-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>



From Damien.LeMoal at wdc.com  Thu Jan 28 00:40:47 2021
From: Damien.LeMoal at wdc.com (Damien Le Moal)
Date: Thu, 28 Jan 2021 05:40:47 +0000
Subject: [PATCH v4 8/8] sd_zbc: clear zone resources for non-zoned case
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
 <20210128044733.503606-9-damien.lemoal@wdc.com>
 <BYAPR04MB49655B5B6075B83CEFE57C6D86BA9@BYAPR04MB4965.namprd04.prod.outlook.com>
Message-ID: <BL0PR04MB651412874770CEDA5314EEC2E7BA9@BL0PR04MB6514.namprd04.prod.outlook.com>

On 2021/01/28 14:38, Chaitanya Kulkarni wrote:
> On 1/27/21 20:47, Damien Le Moal wrote:
>> -void sd_zbc_release_disk(struct scsi_disk *sdkp)
>> +static void sd_zbc_clear_zone_info(struct scsi_disk *sdkp)
>>  {
>> +	/* Serialize against revalidate zones */
>> +	mutex_lock(&sdkp->rev_mutex);
>> +
>>  	kvfree(sdkp->zones_wp_offset);
>>  	sdkp->zones_wp_offset = NULL;
>>  	kfree(sdkp->zone_wp_update_buf);
>>  	sdkp->zone_wp_update_buf = NULL;
>> +
>> +	sdkp->nr_zones = 0;
>> +	sdkp->rev_nr_zones = 0;
>> +	sdkp->zone_blocks = 0;
>> +	sdkp->rev_zone_blocks = 0;
>> +
>> +	mutex_unlock(&sdkp->rev_mutex);
>> +}
>> +
>> +void sd_zbc_release_disk(struct scsi_disk *sdkp)
>> +{
>> +	if (sd_is_zoned(sdkp))
>> +		sd_zbc_clear_zone_info(sdkp);
>>  }
>>  
> If I'm not wrong there is only one caller for sd_zbc_clear_zone_info().
> Is there any reason why sd_zbc_clear_zone_info() is notopen coded with
> a meaningful comment in sd_zbc_release_disk() ? e.g. :-

There are 2 call sites: sd_zbc_read_zones() and sd_zbc_release_disk().

> 
> void sd_zbc_release_disk(struct scsi_disk *sdkp)
> {
> 	if (!sd_is_zoned(sdkp))
> 		return; 
> 	/* Serialize against revalidate zones */
> 	mutex_lock(&sdkp->rev_mutex);
> 
>  	kvfree(sdkp->zones_wp_offset);
>  	sdkp->zones_wp_offset = NULL;
>  	kfree(sdkp->zone_wp_update_buf);
>  	sdkp->zone_wp_update_buf = NULL;
> 
> 	/* clear zone info */
> 	sdkp->nr_zones = 0;
> 	sdkp->rev_nr_zones = 0;
> 	sdkp->zone_blocks = 0;
> 	sdkp->rev_zone_blocks = 0;
> 
> 	mutex_unlock(&sdkp->rev_mutex);
>  }
> 
> 
> unless I miss something, in either case LGTM.
> 
> Reviewed-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
> 
> 


-- 
Damien Le Moal
Western Digital Research


From sagi at grimberg.me  Thu Jan 28 02:54:58 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Wed, 27 Jan 2021 23:54:58 -0800
Subject: [PATCH] nvme-tcp: proper handling of tcp socket closing flows
In-Reply-To: <20210126153757.99451-1-elad.grupi@dell.com>
References: <20210126153757.99451-1-elad.grupi@dell.com>
Message-ID: <8eead62d-a96b-46b7-fc87-71e599d3d83d@grimberg.me>

> From: Elad Grupi <elad.grupi at dell.com>
> 
> avoid calling nvmet_tcp_release_queue_work if tcp socket was closed
> before setting the sk callbacks.

But we need to call the release_queue work, not sure I understand
how this works.

> 
> prevent io_work from enqueuing while closing the tcp queue to
> avoid race with nvmet_tcp_release_queue_work.

io_work is going to run with release_queue_work, because
it is also coming from the backend completion. The right
way to solve this is to correctly fence them.

Can you describe the exact race you are referring to?

> 
> Signed-off-by: Elad Grupi <elad.grupi at dell.com>
> ---
>   drivers/nvme/target/tcp.c | 26 +++++++++++++++++++++-----
>   1 file changed, 21 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
> index d535080b781f..937f2a746d8b 100644
> --- a/drivers/nvme/target/tcp.c
> +++ b/drivers/nvme/target/tcp.c
> @@ -647,7 +647,7 @@ static int nvmet_tcp_try_send_one(struct nvmet_tcp_queue *queue,
>   	struct nvmet_tcp_cmd *cmd = queue->snd_cmd;
>   	int ret = 0;
>   
> -	if (!cmd || queue->state == NVMET_TCP_Q_DISCONNECTING) {
> +	if (!cmd) {
>   		cmd = nvmet_tcp_fetch_cmd(queue);
>   		if (unlikely(!cmd))
>   			return 0;
> @@ -1196,7 +1196,7 @@ static void nvmet_tcp_io_work(struct work_struct *w)
>   	/*
>   	 * We exahusted our budget, requeue our selves
>   	 */
> -	if (pending)
> +	if (pending && queue->state != NVMET_TCP_Q_DISCONNECTING)
>   		queue_work_on(queue->cpu, nvmet_tcp_wq, &queue->io_work);
>   }
>   
> @@ -1453,9 +1453,27 @@ static int nvmet_tcp_set_queue_sock(struct nvmet_tcp_queue *queue)
>   	sock->sk->sk_state_change = nvmet_tcp_state_change;
>   	queue->write_space = sock->sk->sk_write_space;
>   	sock->sk->sk_write_space = nvmet_tcp_write_space;
> +
> +	switch (sk->sk_state) {
> +	case TCP_FIN_WAIT1:
> +	case TCP_CLOSE_WAIT:
> +	case TCP_CLOSE:
> +		/* FALLTHRU */
> +		sock->sk->sk_data_ready =  queue->data_ready;
> +		sock->sk->sk_state_change = queue->state_change;
> +		sock->sk->sk_write_space = queue->write_space;
> +		sk->sk_user_data = NULL;
> +		queue->state = NVMET_TCP_Q_DISCONNECTING;
> +		ret = -ENOTCONN;
> +		break;
> +	default:
> +		queue_work_on(queue->cpu, nvmet_tcp_wq, &queue->io_work);
> +		ret = 0;
> +	}
> +
>   	write_unlock_bh(&sock->sk->sk_callback_lock);
>   
> -	return 0;
> +	return ret;
>   }
>   
>   static int nvmet_tcp_alloc_queue(struct nvmet_tcp_port *port,
> @@ -1506,8 +1524,6 @@ static int nvmet_tcp_alloc_queue(struct nvmet_tcp_port *port,
>   	if (ret)
>   		goto out_destroy_sq;
>   
> -	queue_work_on(queue->cpu, nvmet_tcp_wq, &queue->io_work);
> -
>   	return 0;
>   out_destroy_sq:
>   	mutex_lock(&nvmet_tcp_queue_mutex);
> 


From dwagner at suse.de  Thu Jan 28 02:58:37 2021
From: dwagner at suse.de (Daniel Wagner)
Date: Thu, 28 Jan 2021 08:58:37 +0100
Subject: [PATCH v2] nvme-multipath: Early exit if no path is available
In-Reply-To: <db9baae0-547c-7ff4-8b2c-0b95f14be67c@huawei.com>
References: <20210127103033.15318-1-dwagner@suse.de>
 <db9baae0-547c-7ff4-8b2c-0b95f14be67c@huawei.com>
Message-ID: <20210128075837.u5u56t23fq5gu6ou@beryllium.lan>

On Thu, Jan 28, 2021 at 09:31:30AM +0800, Chao Leng wrote:
> > --- a/drivers/nvme/host/multipath.c
> > +++ b/drivers/nvme/host/multipath.c
> > @@ -221,7 +221,7 @@ static struct nvme_ns *nvme_round_robin_path(struct nvme_ns_head *head,
> >   	}
> >   	for (ns = nvme_next_ns(head, old);
> > -	     ns != old;
> > +	     ns && ns != old;
> nvme_round_robin_path just be called when !"old".
> nvme_next_ns should not return NULL when !"old".
> It seems unnecessary to add checking "ns".

The problem is when we enter nvme_round_robin_path() and there is no
path available. In this case the initialization ns = nvme_next_ns(head,
old) could return a NULL pointer.


From gregkh at linuxfoundation.org  Thu Jan 28 03:04:50 2021
From: gregkh at linuxfoundation.org (Greg KH)
Date: Thu, 28 Jan 2021 09:04:50 +0100
Subject: [PATCH 0/3] Adding offset keeping option when mapping data via
 SWIOTLB.*
In-Reply-To: <20210128003829.1892018-1-jxgao@google.com>
References: <20210128003829.1892018-1-jxgao@google.com>
Message-ID: <YBJwImu3RoQsGhJq@kroah.com>

On Wed, Jan 27, 2021 at 04:38:26PM -0800, Jianxiong Gao wrote:
> NVMe driver and other applications may depend on the data offset
> to operate correctly. Currently when unaligned data is mapped via
> SWIOTLB, the data is mapped as slab aligned with the SWIOTLB. This
> patch adds an option to make sure the mapped data preserves its
> offset of the orginal addrss.
> 
> Without the patch when creating xfs formatted disk on NVMe backends,
> with swiotlb=force in kernel boot option, creates the following error:
> meta-data=/dev/nvme2n1           isize=512    agcount=4, agsize=131072 blks
>          =                       sectsz=512   attr=2, projid32bit=1
>          =                       crc=1        finobt=1, sparse=0, rmapbt=0, refl
> ink=0
> data     =                       bsize=4096   blocks=524288, imaxpct=25
>          =                       sunit=0      swidth=0 blks
> naming   =version 2              bsize=4096   ascii-ci=0 ftype=1
> log      =internal log           bsize=4096   blocks=2560, version=2
>          =                       sectsz=512   sunit=0 blks, lazy-count=1
> realtime =none                   extsz=4096   blocks=0, rtextents=0
> mkfs.xfs: pwrite failed: Input/output error
> 
> Jianxiong Gao (3):
>   Adding page_offset_mask to device_dma_parameters
>   Add swiotlb offset preserving mapping when
>     dma_dma_parameters->page_offset_mask is non zero.
>   Adding device_dma_parameters->offset_preserve_mask to NVMe driver.


Hi,

This is the friendly patch-bot of Greg Kroah-Hartman.  You have sent him
a patch that has triggered this response.  He used to manually respond
to these common problems, but in order to save his sanity (he kept
writing the same thing over and over, yet to different people), I was
created.  Hopefully you will not take offence and will fix the problem
in your patch and resubmit it so that it can be accepted into the Linux
kernel tree.

You are receiving this message because of the following common error(s)
as indicated below:

- You did not write a descriptive Subject: for the patch, allowing Greg,
  and everyone else, to know what this patch is all about.  Please read
  the section entitled "The canonical patch format" in the kernel file,
  Documentation/SubmittingPatches for what a proper Subject: line should
  look like.

If you wish to discuss this problem further, or you have questions about
how to resolve this issue, please feel free to respond to this email and
Greg will reply once he has dug out from the pending patches received
from other developers.

thanks,

greg k-h's patch email bot


From sagi at grimberg.me  Thu Jan 28 03:15:48 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Thu, 28 Jan 2021 00:15:48 -0800
Subject: [PATCH 1/5] nvme: add NVME_REQ_CANCELLED flag in
 nvme_cancel_request()
In-Reply-To: <20210127103326.16191-2-hare@suse.de>
References: <20210127103326.16191-1-hare@suse.de>
 <20210127103326.16191-2-hare@suse.de>
Message-ID: <6be12f35-7674-83ff-b6ef-ee51170e8d79@grimberg.me>

> NVME_REQ_CANCELLED is translated into -EINTR in nvme_submit_sync_cmd(),
> so we should be setting this flags during nvme_cancel_request() to
> ensure that the callers to nvme_submit_sync_cmd() will get the correct
> error code when the controller is reset.

We will have an issue here. Because now nvme_validate_ns will return
EINTR, which means that now scans failing to validate during resets
will now end up incorrectly removing the namespace:

--
out:
         /*
          * Only remove the namespace if we got a fatal error back from the
          * device, otherwise ignore the error and just move on.
          *
          * TODO: we should probably schedule a delayed retry here.
          */
         if (ret && ret != -ENOMEM && !(ret > 0 && !(ret & NVME_SC_DNR)))
                 nvme_ns_remove(ns);
--

Did you check resets loop with scans with this?

If we go down this path (we already had this discussion in the
past), we need to decide on either of:
- Don't remove the namespace for any of the return codes from
   nvme_submit_sync_cmd (understanding that this may be just a
   transport issue).
- Or, return the raw positive nvme status (which doesn't have
   the DNR bit set) and make sure we return ret codes on top.

But this change alone, re-triggers a condition that during
resets a namespace is incorrectly removed.


From sagi at grimberg.me  Thu Jan 28 03:39:27 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Thu, 28 Jan 2021 00:39:27 -0800
Subject: [PATCH v4 4/5] nvme-rdma: avoid IO error for nvme native multipath
In-Reply-To: <20210126081539.13320-5-lengchao@huawei.com>
References: <20210126081539.13320-1-lengchao@huawei.com>
 <20210126081539.13320-5-lengchao@huawei.com>
Message-ID: <5a368693-65fd-1bdf-924a-f90df7f59b2a@grimberg.me>


> @@ -2084,8 +2085,10 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
>   
>   	err = nvme_rdma_post_send(queue, sqe, req->sge, req->num_sge,
>   			req->mr ? &req->reg_wr.wr : NULL);
> -	if (unlikely(err))
> +	if (unlikely(err)) {
> +		driver_error = true;
>   		goto err_unmap;

Why not just call set the status and call nvme_rdma_complete_rq and
return here?


From hch at lst.de  Thu Jan 28 04:17:10 2021
From: hch at lst.de (Christoph Hellwig)
Date: Thu, 28 Jan 2021 10:17:10 +0100
Subject: [PATCH v4 2/8] nvme: cleanup zone information initialization
In-Reply-To: <20210128044733.503606-3-damien.lemoal@wdc.com>
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
 <20210128044733.503606-3-damien.lemoal@wdc.com>
Message-ID: <20210128091710.GA1959@lst.de>

>  int nvme_revalidate_zones(struct nvme_ns *ns)
>  {
> -	struct request_queue *q = ns->queue;
> -	int ret;
> -
> -	ret = blk_revalidate_disk_zones(ns->disk, NULL);
> -	if (!ret)
> -		blk_queue_max_zone_append_sectors(q, ns->ctrl->max_zone_append);
> -	return ret;
> +	return blk_revalidate_disk_zones(ns->disk, NULL);

We can just kill off nvme_revalidate_zones now and open code it in
the caller as the stub is no needed now that blk_queue_is_zoned always
return false for the !CONFIG_BLK_DEV_ZONED case.

Otherwise this look great, nice cleanup:

Reviewed-by: Christoph Hellwig <hch at lst.de>


From hch at lst.de  Thu Jan 28 04:17:27 2021
From: hch at lst.de (Christoph Hellwig)
Date: Thu, 28 Jan 2021 10:17:27 +0100
Subject: [PATCH v4 3/8] nullb: use blk_queue_set_zoned() to setup zoned
 devices
In-Reply-To: <20210128044733.503606-4-damien.lemoal@wdc.com>
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
 <20210128044733.503606-4-damien.lemoal@wdc.com>
Message-ID: <20210128091727.GB1959@lst.de>

On Thu, Jan 28, 2021 at 01:47:28PM +0900, Damien Le Moal wrote:
> Use blk_queue_set_zoned() to set a nullb device zone model instead of
> directly assigning the device queue zoned limit. This initialization of
> the devicve zoned model as well as the setup of the queue flag
> QUEUE_FLAG_ZONE_RESETALL and of the device queue elevator feature are
> moved from null_init_zoned_dev() to null_register_zoned_dev() so that
> the initialization of the queue limits is done when the gendisk of the
> nullb device is available.

Looks good,

Reviewed-by: Christoph Hellwig <hch at lst.de>


From hch at lst.de  Thu Jan 28 04:17:45 2021
From: hch at lst.de (Christoph Hellwig)
Date: Thu, 28 Jan 2021 10:17:45 +0100
Subject: [PATCH v4 4/8] block: use blk_queue_set_zoned in add_partition()
In-Reply-To: <20210128044733.503606-5-damien.lemoal@wdc.com>
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
 <20210128044733.503606-5-damien.lemoal@wdc.com>
Message-ID: <20210128091745.GC1959@lst.de>

On Thu, Jan 28, 2021 at 01:47:29PM +0900, Damien Le Moal wrote:
> When changing the zoned model of host-aware zoned block devices, use
> blk_queue_set_zoned() instead of directly assigning the gendisk queue
> zoned limit.
> 
> Signed-off-by: Damien Le Moal <damien.lemoal at wdc.com>

Looks good,

Reviewed-by: Christoph Hellwig <hch at lst.de>


From lengchao at huawei.com  Thu Jan 28 04:18:56 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 28 Jan 2021 17:18:56 +0800
Subject: [PATCH v2] nvme-multipath: Early exit if no path is available
In-Reply-To: <20210128075837.u5u56t23fq5gu6ou@beryllium.lan>
References: <20210127103033.15318-1-dwagner@suse.de>
 <db9baae0-547c-7ff4-8b2c-0b95f14be67c@huawei.com>
 <20210128075837.u5u56t23fq5gu6ou@beryllium.lan>
Message-ID: <69575290-200e-b4a1-4269-c71e4c2cc37b@huawei.com>



On 2021/1/28 15:58, Daniel Wagner wrote:
> On Thu, Jan 28, 2021 at 09:31:30AM +0800, Chao Leng wrote:
>>> --- a/drivers/nvme/host/multipath.c
>>> +++ b/drivers/nvme/host/multipath.c
>>> @@ -221,7 +221,7 @@ static struct nvme_ns *nvme_round_robin_path(struct nvme_ns_head *head,
>>>    	}
>>>    	for (ns = nvme_next_ns(head, old);
>>> -	     ns != old;
>>> +	     ns && ns != old;
>> nvme_round_robin_path just be called when !"old".
>> nvme_next_ns should not return NULL when !"old".
>> It seems unnecessary to add checking "ns".
> 
> The problem is when we enter nvme_round_robin_path() and there is no
> path available. In this case the initialization ns = nvme_next_ns(head,
> old) could return a NULL pointer."old" should not be NULL, so there is at least one path that is "old".
It is impossible to return NULL for nvme_next_ns(head, old).
> .
> 


From hch at lst.de  Thu Jan 28 04:19:30 2021
From: hch at lst.de (Christoph Hellwig)
Date: Thu, 28 Jan 2021 10:19:30 +0100
Subject: [PATCH v4 5/8] block: introduce zone_write_granularity limit
In-Reply-To: <20210128044733.503606-6-damien.lemoal@wdc.com>
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
 <20210128044733.503606-6-damien.lemoal@wdc.com>
Message-ID: <20210128091930.GD1959@lst.de>

> +	t->zone_write_granularity = max(t->zone_write_granularity,
> +					b->zone_write_granularity);
>  	t->zoned = max(t->zoned, b->zoned);

Totally superficial nit:  it would read a little nicer if
zone_write_granularity is assigned after the zoned value.

Otherwise this looks perfect.

Reviewed-by: Christoph Hellwig <hch at lst.de>


From hch at lst.de  Thu Jan 28 04:21:07 2021
From: hch at lst.de (Christoph Hellwig)
Date: Thu, 28 Jan 2021 10:21:07 +0100
Subject: [PATCH v4 7/8] block: introduce blk_queue_clear_zone_settings()
In-Reply-To: <20210128044733.503606-8-damien.lemoal@wdc.com>
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
 <20210128044733.503606-8-damien.lemoal@wdc.com>
Message-ID: <20210128092107.GE1959@lst.de>

On Thu, Jan 28, 2021 at 01:47:32PM +0900, Damien Le Moal wrote:
> Introduce the internal function blk_queue_clear_zone_settings() to
> cleanup all limits and resources related to zoned block devices. This
> new function is called from blk_queue_set_zoned() when a disk zoned
> model is set to BLK_ZONED_NONE. This particular case can happens when a
> partition is created on a host-aware scsi disk.

Shouldn't we just do all this work when blk_queue_set_zoned is called
with a BLK_ZONED_NONE argument?  That seems like the more obvious API
to me.


From hare at suse.de  Thu Jan 28 04:23:42 2021
From: hare at suse.de (Hannes Reinecke)
Date: Thu, 28 Jan 2021 10:23:42 +0100
Subject: [PATCH v2] nvme-multipath: Early exit if no path is available
In-Reply-To: <69575290-200e-b4a1-4269-c71e4c2cc37b@huawei.com>
References: <20210127103033.15318-1-dwagner@suse.de>
 <db9baae0-547c-7ff4-8b2c-0b95f14be67c@huawei.com>
 <20210128075837.u5u56t23fq5gu6ou@beryllium.lan>
 <69575290-200e-b4a1-4269-c71e4c2cc37b@huawei.com>
Message-ID: <8704038d-0b71-5c9c-2d2b-a9ff2166dbe4@suse.de>

On 1/28/21 10:18 AM, Chao Leng wrote:
> 
> 
> On 2021/1/28 15:58, Daniel Wagner wrote:
>> On Thu, Jan 28, 2021 at 09:31:30AM +0800, Chao Leng wrote:
>>>> --- a/drivers/nvme/host/multipath.c
>>>> +++ b/drivers/nvme/host/multipath.c
>>>> @@ -221,7 +221,7 @@ static struct nvme_ns 
>>>> *nvme_round_robin_path(struct nvme_ns_head *head,
>>>> ?????? }
>>>> ?????? for (ns = nvme_next_ns(head, old);
>>>> -???????? ns != old;
>>>> +???????? ns && ns != old;
>>> nvme_round_robin_path just be called when !"old".
>>> nvme_next_ns should not return NULL when !"old".
>>> It seems unnecessary to add checking "ns".
>>
>> The problem is when we enter nvme_round_robin_path() and there is no
>> path available. In this case the initialization ns = nvme_next_ns(head,
>> old) could return a NULL pointer."old" should not be NULL, so there is 
>> at least one path that is "old".
> It is impossible to return NULL for nvme_next_ns(head, old).

No. list_next_or_null_rcu()/list_first_or_null_rcu() will return NULL 
when then end of the list is reached.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare at suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 N?rnberg
HRB 36809 (AG N?rnberg), Gesch?ftsf?hrer: Felix Imend?rffer


From hch at lst.de  Thu Jan 28 04:24:06 2021
From: hch at lst.de (Christoph Hellwig)
Date: Thu, 28 Jan 2021 10:24:06 +0100
Subject: [PATCH v4 8/8] sd_zbc: clear zone resources for non-zoned case
In-Reply-To: <20210128044733.503606-9-damien.lemoal@wdc.com>
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
 <20210128044733.503606-9-damien.lemoal@wdc.com>
Message-ID: <20210128092406.GA2607@lst.de>

On Thu, Jan 28, 2021 at 01:47:33PM +0900, Damien Le Moal wrote:
> For host-aware ZBC disk, setting the device zoned model to BLK_ZONED_HA
> using blk_queue_set_zoned() in sd_read_block_characteristics() may
> result in the block device effective zoned model to be "none"
> (BLK_ZONED_NONE) if partitions are present on the device. In this case,
> sd_zbc_read_zones() should not setup the zone related queue limits for
> the disk so that the device limits and configuration is consistent with
> a regular disk and resources not uselessly allocated (e.g. the zone
> write pointer tracking array for zone append emulation).
> 
> Furthermore, if the disk zoned model changes at run time due to the
> creation of a partition by the user, the zone related resources can be
> released.
> 
> Fix both problems by introducing the function sd_zbc_clear_zone_info()
> to reset the scsi disk zone information and free resources and by
> returning early in sd_zbc_read_zones() for a block device that has a
> zoned model equal to BLK_ZONED_NONE.

So creating the partition doesn't even call into the driver, which
means we'll leak the info for now.  But I guess the next revalidate
will simply clean it up, so it is not a major issue.

Looks good:

Reviewed-by: Christoph Hellwig <hch at lst.de>


From Damien.LeMoal at wdc.com  Thu Jan 28 04:27:41 2021
From: Damien.LeMoal at wdc.com (Damien Le Moal)
Date: Thu, 28 Jan 2021 09:27:41 +0000
Subject: [PATCH v4 2/8] nvme: cleanup zone information initialization
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
 <20210128044733.503606-3-damien.lemoal@wdc.com>
 <20210128091710.GA1959@lst.de>
Message-ID: <BL0PR04MB6514F6AD357E545CBCAB877DE7BA9@BL0PR04MB6514.namprd04.prod.outlook.com>

On 2021/01/28 18:17, Christoph Hellwig wrote:
>>  int nvme_revalidate_zones(struct nvme_ns *ns)
>>  {
>> -	struct request_queue *q = ns->queue;
>> -	int ret;
>> -
>> -	ret = blk_revalidate_disk_zones(ns->disk, NULL);
>> -	if (!ret)
>> -		blk_queue_max_zone_append_sectors(q, ns->ctrl->max_zone_append);
>> -	return ret;
>> +	return blk_revalidate_disk_zones(ns->disk, NULL);
> 
> We can just kill off nvme_revalidate_zones now and open code it in
> the caller as the stub is no needed now that blk_queue_is_zoned always
> return false for the !CONFIG_BLK_DEV_ZONED case.

I tried that first, but it did not work. I end up with
blk_revalidate_disk_zones() undefined error with !CONFIG_BLK_DEV_ZONED.
This is because blk_queue_is_zoned() is *not* stubbed for !CONFIG_BLK_DEV_ZONED.
It will simply always return 0/none in that case. We would need to have:

if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) && blk_queue_is_zoned()) {
	ret = blk_revalidate_disk_zones(ns->disk, NULL);
	...

Or stub blk_queue_is_zoned()...

> 
> Otherwise this look great, nice cleanup:
> 
> Reviewed-by: Christoph Hellwig <hch at lst.de>
> 


-- 
Damien Le Moal
Western Digital Research


From lengchao at huawei.com  Thu Jan 28 04:31:47 2021
From: lengchao at huawei.com (Chao Leng)
Date: Thu, 28 Jan 2021 17:31:47 +0800
Subject: [PATCH v4 4/5] nvme-rdma: avoid IO error for nvme native multipath
In-Reply-To: <5a368693-65fd-1bdf-924a-f90df7f59b2a@grimberg.me>
References: <20210126081539.13320-1-lengchao@huawei.com>
 <20210126081539.13320-5-lengchao@huawei.com>
 <5a368693-65fd-1bdf-924a-f90df7f59b2a@grimberg.me>
Message-ID: <9c30b18a-6fdd-be1c-f3bc-1d44c35ae274@huawei.com>



On 2021/1/28 16:39, Sagi Grimberg wrote:
> 
>> @@ -2084,8 +2085,10 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
>> ????? err = nvme_rdma_post_send(queue, sqe, req->sge, req->num_sge,
>> ????????????? req->mr ? &req->reg_wr.wr : NULL);
>> -??? if (unlikely(err))
>> +??? if (unlikely(err)) {
>> +??????? driver_error = true;
>> ????????? goto err_unmap;
> 
> Why not just call set the status and call nvme_rdma_complete_rq and
> return here?
If the err is ENOMEM or EAGAIN, I am not sure the err must be a
path-related error for all HBA drivers. So reused the error check code.
I think it would be more reasonable to assume any errors returned by HBA
driver as path-related errors.
If you think so, I will modify it in next patch version.


From Damien.LeMoal at wdc.com  Thu Jan 28 04:32:22 2021
From: Damien.LeMoal at wdc.com (Damien Le Moal)
Date: Thu, 28 Jan 2021 09:32:22 +0000
Subject: [PATCH v4 7/8] block: introduce blk_queue_clear_zone_settings()
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
 <20210128044733.503606-8-damien.lemoal@wdc.com>
 <20210128092107.GE1959@lst.de>
Message-ID: <BL0PR04MB6514021E07E861070BDD852EE7BA9@BL0PR04MB6514.namprd04.prod.outlook.com>

On 2021/01/28 18:21, Christoph Hellwig wrote:
> On Thu, Jan 28, 2021 at 01:47:32PM +0900, Damien Le Moal wrote:
>> Introduce the internal function blk_queue_clear_zone_settings() to
>> cleanup all limits and resources related to zoned block devices. This
>> new function is called from blk_queue_set_zoned() when a disk zoned
>> model is set to BLK_ZONED_NONE. This particular case can happens when a
>> partition is created on a host-aware scsi disk.
> 
> Shouldn't we just do all this work when blk_queue_set_zoned is called
> with a BLK_ZONED_NONE argument?  That seems like the more obvious API
> to me.

That is what I did. blk_queue_set_zoned() calls blk_queue_clear_zone_settings()
for BLK_ZONED_NONE case. I simply did not open code the cleanups in that
functions because it is simpler to stub only blk_queue_clear_zone_settings()
rather than having conditionals in blk_queue_set_zoned(). That also puts the
cleanup function together with the code that allocates most resources in
blk-zoned.c. Easier to not overlook something.



-- 
Damien Le Moal
Western Digital Research


From hch at lst.de  Thu Jan 28 04:32:40 2021
From: hch at lst.de (Christoph Hellwig)
Date: Thu, 28 Jan 2021 10:32:40 +0100
Subject: [PATCH v4 2/8] nvme: cleanup zone information initialization
In-Reply-To: <BL0PR04MB6514F6AD357E545CBCAB877DE7BA9@BL0PR04MB6514.namprd04.prod.outlook.com>
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
 <20210128044733.503606-3-damien.lemoal@wdc.com>
 <20210128091710.GA1959@lst.de>
 <BL0PR04MB6514F6AD357E545CBCAB877DE7BA9@BL0PR04MB6514.namprd04.prod.outlook.com>
Message-ID: <20210128093240.GA3212@lst.de>

On Thu, Jan 28, 2021 at 09:27:41AM +0000, Damien Le Moal wrote:
> 
> I tried that first, but it did not work. I end up with
> blk_revalidate_disk_zones() undefined error with !CONFIG_BLK_DEV_ZONED.
> This is because blk_queue_is_zoned() is *not* stubbed for !CONFIG_BLK_DEV_ZONED.
> It will simply always return 0/none in that case. We would need to have:

Hmm.  blk_queue_is_zoned is calls blk_queue_zoned_model, which
always returns BLK_ZONED_NONE for !CONFIG_BLK_DEV_ZONED, and I thought we
rely on that elsewhere in nvme.  That is a fairly recent change from me,
though.

> 
> if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) && blk_queue_is_zoned()) {
> 	ret = blk_revalidate_disk_zones(ns->disk, NULL);
> 	...
> 
> Or stub blk_queue_is_zoned()...

If the above really doesn't work we should properly stub it out.

Anyway, I think we can go with your current patch:

Reviewed-by: Christoph Hellwig <hch at lst.de>

and refine all the zoned stubs later.  I have a few more ideas for
improvements there anyway.


From hch at lst.de  Thu Jan 28 04:33:10 2021
From: hch at lst.de (Christoph Hellwig)
Date: Thu, 28 Jan 2021 10:33:10 +0100
Subject: [PATCH v4 7/8] block: introduce blk_queue_clear_zone_settings()
In-Reply-To: <BL0PR04MB6514021E07E861070BDD852EE7BA9@BL0PR04MB6514.namprd04.prod.outlook.com>
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
 <20210128044733.503606-8-damien.lemoal@wdc.com>
 <20210128092107.GE1959@lst.de>
 <BL0PR04MB6514021E07E861070BDD852EE7BA9@BL0PR04MB6514.namprd04.prod.outlook.com>
Message-ID: <20210128093310.GB3212@lst.de>

On Thu, Jan 28, 2021 at 09:32:22AM +0000, Damien Le Moal wrote:
> On 2021/01/28 18:21, Christoph Hellwig wrote:
> > On Thu, Jan 28, 2021 at 01:47:32PM +0900, Damien Le Moal wrote:
> >> Introduce the internal function blk_queue_clear_zone_settings() to
> >> cleanup all limits and resources related to zoned block devices. This
> >> new function is called from blk_queue_set_zoned() when a disk zoned
> >> model is set to BLK_ZONED_NONE. This particular case can happens when a
> >> partition is created on a host-aware scsi disk.
> > 
> > Shouldn't we just do all this work when blk_queue_set_zoned is called
> > with a BLK_ZONED_NONE argument?  That seems like the more obvious API
> > to me.
> 
> That is what I did. blk_queue_set_zoned() calls blk_queue_clear_zone_settings()
> for BLK_ZONED_NONE case. I simply did not open code the cleanups in that
> functions because it is simpler to stub only blk_queue_clear_zone_settings()
> rather than having conditionals in blk_queue_set_zoned(). That also puts the
> cleanup function together with the code that allocates most resources in
> blk-zoned.c. Easier to not overlook something.

Ok, looks good to me then:

Reviewed-by: Christoph Hellwig <hch at lst.de>


From Damien.LeMoal at wdc.com  Thu Jan 28 04:36:47 2021
From: Damien.LeMoal at wdc.com (Damien Le Moal)
Date: Thu, 28 Jan 2021 09:36:47 +0000
Subject: [PATCH v4 8/8] sd_zbc: clear zone resources for non-zoned case
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
 <20210128044733.503606-9-damien.lemoal@wdc.com>
 <20210128092406.GA2607@lst.de>
Message-ID: <BL0PR04MB6514062937FF5BE302A27C8FE7BA9@BL0PR04MB6514.namprd04.prod.outlook.com>

On 2021/01/28 18:24, Christoph Hellwig wrote:
> On Thu, Jan 28, 2021 at 01:47:33PM +0900, Damien Le Moal wrote:
>> For host-aware ZBC disk, setting the device zoned model to BLK_ZONED_HA
>> using blk_queue_set_zoned() in sd_read_block_characteristics() may
>> result in the block device effective zoned model to be "none"
>> (BLK_ZONED_NONE) if partitions are present on the device. In this case,
>> sd_zbc_read_zones() should not setup the zone related queue limits for
>> the disk so that the device limits and configuration is consistent with
>> a regular disk and resources not uselessly allocated (e.g. the zone
>> write pointer tracking array for zone append emulation).
>>
>> Furthermore, if the disk zoned model changes at run time due to the
>> creation of a partition by the user, the zone related resources can be
>> released.
>>
>> Fix both problems by introducing the function sd_zbc_clear_zone_info()
>> to reset the scsi disk zone information and free resources and by
>> returning early in sd_zbc_read_zones() for a block device that has a
>> zoned model equal to BLK_ZONED_NONE.
> 
> So creating the partition doesn't even call into the driver, which
> means we'll leak the info for now.  But I guess the next revalidate
> will simply clean it up, so it is not a major issue.

Exactly. But the leak is only for the sd level resources now.
blk_queue_set_zoned() cleans up everything else.
The super annoying thing is that deleting all partitions leaves that disk in
regular mode instead of returning it to zoned mode. Need to wait for a
revalidate or for a manual rescan for that to happen. I wonder if we should not
trigger a revalidate, always, to avoid that the user sees the device type
suddenly changing long after the partitions were deleted...
Adding such revalidate for partition creation would solve the "leak" problem (or
rather the lack of cleaning) too.

> 
> Looks good:
> 
> Reviewed-by: Christoph Hellwig <hch at lst.de>
> 


-- 
Damien Le Moal
Western Digital Research


From dwagner at suse.de  Thu Jan 28 04:40:04 2021
From: dwagner at suse.de (Daniel Wagner)
Date: Thu, 28 Jan 2021 10:40:04 +0100
Subject: [PATCH v2] nvme-multipath: Early exit if no path is available
In-Reply-To: <69575290-200e-b4a1-4269-c71e4c2cc37b@huawei.com>
References: <20210127103033.15318-1-dwagner@suse.de>
 <db9baae0-547c-7ff4-8b2c-0b95f14be67c@huawei.com>
 <20210128075837.u5u56t23fq5gu6ou@beryllium.lan>
 <69575290-200e-b4a1-4269-c71e4c2cc37b@huawei.com>
Message-ID: <20210128094004.erwnszjqcxlsi2kd@beryllium.lan>

On Thu, Jan 28, 2021 at 05:18:56PM +0800, Chao Leng wrote:
> It is impossible to return NULL for nvme_next_ns(head, old).

 block nvme0n1: no usable path - requeuing I/O
 block nvme0n1: no usable path - requeuing I/O
 block nvme0n1: no usable path - requeuing I/O
 block nvme0n1: no usable path - requeuing I/O
 block nvme0n1: no usable path - requeuing I/O
 block nvme0n1: no usable path - requeuing I/O
 BUG: kernel NULL pointer dereference, address: 0000000000000068
 #PF: supervisor read access in kernel mode
 #PF: error_code(0x0000) - not-present page
 PGD 8000000ff67bc067 P4D 8000000ff67bc067 PUD ff9ac9067 PMD 0 
 Oops: 0000 [#1] SMP PTI
 CPU: 23 PID: 15759 Comm: dt.21.15 Kdump: loaded Tainted: G            E       5.3.18-0.gc9fe679-default #1 SLE15-SP2 (unreleased)
 Hardware name: FUJITSU PRIMERGY RX2540 M2/D3289-B1, BIOS V5.0.0.11 R1.18.0 for D3289-B1x                    02/06/2018
 RIP: 0010:nvme_ns_head_make_request+0x1d1/0x430 [nvme_core]
 Code: 54 24 10 0f 84 c9 01 00 00 48 8b 54 24 10 48 83 ea 30 0f 84 ba 01 00 00 48 39 d0 0f 84 01 02 00 00 31 ff eb 05 48 39 d0 74 67 <48> 8b 72 68 83 e6 04 75 13 48 8b 72 68 83 e6 01 75 0a 48 8b 72 10
 RSP: 0018:ffffa69d08017af8 EFLAGS: 00010246
 RAX: ffff92f261d87800 RBX: ffff92fa555b0010 RCX: ffff92fa555bc570
 RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
 RBP: 0000000000000001 R08: 0000000000001000 R09: 0000000000001000
 R10: ffffa69d080179a8 R11: ffff92f264f0c1c0 R12: ffff92f264f7f000
 R13: ffff92fa555b0000 R14: 0000000000000001 R15: 0000000000000000
 FS:  00007f3962bae700(0000) GS:ffff92f29ffc0000(0000) knlGS:0000000000000000
 CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
 CR2: 0000000000000068 CR3: 0000000fd69a2002 CR4: 00000000003606e0
 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
 Call Trace:
  generic_make_request+0x121/0x300
  ? submit_bio+0x42/0x1c0
  submit_bio+0x42/0x1c0
  ext4_io_submit+0x49/0x60 [ext4]
  ext4_writepages+0x625/0xe90 [ext4]
  ? do_writepages+0x4b/0xe0
  ? ext4_mark_inode_dirty+0x1d0/0x1d0 [ext4]
  do_writepages+0x4b/0xe0
  ? __generic_file_write_iter+0x192/0x1c0
  ? __filemap_fdatawrite_range+0xcb/0x100
  __filemap_fdatawrite_range+0xcb/0x100
  ? ext4_file_write_iter+0x128/0x3c0 [ext4]
  file_write_and_wait_range+0x5e/0xb0
  __generic_file_fsync+0x22/0xb0
  ext4_sync_file+0x1f7/0x3c0 [ext4]
  do_fsync+0x38/0x60
  __x64_sys_fsync+0x10/0x20
  do_syscall_64+0x5b/0x1e0
entry_SYSCALL_64_after_hwframe+0x44/0xa9

You can't see exactly where it dies but I followed the assembly to
nvme_round_robin_path(). Maybe it's not the initial nvme_next_ns(head,
old) which returns NULL but nvme_next_ns() is returning NULL eventually
(list_next_or_null_rcu()).

And I have positive feedback, this patch fixes the above problem.



From Johannes.Thumshirn at wdc.com  Thu Jan 28 05:20:46 2021
From: Johannes.Thumshirn at wdc.com (Johannes Thumshirn)
Date: Thu, 28 Jan 2021 10:20:46 +0000
Subject: [PATCH v4 1/8] block: document zone_append_max_bytes attribute
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
 <20210128044733.503606-2-damien.lemoal@wdc.com>
Message-ID: <SN4PR0401MB3598E30093CC3EF92E0397839BBA9@SN4PR0401MB3598.namprd04.prod.outlook.com>

Looks good,
Reviewed-by: Johannes Thumshirn <johannes.thumshirn at wdc.com>


From Johannes.Thumshirn at wdc.com  Thu Jan 28 06:17:59 2021
From: Johannes.Thumshirn at wdc.com (Johannes Thumshirn)
Date: Thu, 28 Jan 2021 11:17:59 +0000
Subject: [PATCH v4 3/8] nullb: use blk_queue_set_zoned() to setup zoned
 devices
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
 <20210128044733.503606-4-damien.lemoal@wdc.com>
Message-ID: <SN4PR0401MB3598C3C81B68C794535E2C959BBA9@SN4PR0401MB3598.namprd04.prod.outlook.com>

Looks good,
Reviewed-by: Johannes Thumshirn <johannes.thumshirn at wdc.com>


From Johannes.Thumshirn at wdc.com  Thu Jan 28 06:28:40 2021
From: Johannes.Thumshirn at wdc.com (Johannes Thumshirn)
Date: Thu, 28 Jan 2021 11:28:40 +0000
Subject: [PATCH v4 4/8] block: use blk_queue_set_zoned in add_partition()
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
 <20210128044733.503606-5-damien.lemoal@wdc.com>
Message-ID: <SN4PR0401MB35983F79650FF07FEE3DDA3C9BBA9@SN4PR0401MB3598.namprd04.prod.outlook.com>

Looks good,
Reviewed-by: Johannes Thumshirn <johannes.thumshirn at wdc.com>


From Johannes.Thumshirn at wdc.com  Thu Jan 28 06:32:00 2021
From: Johannes.Thumshirn at wdc.com (Johannes Thumshirn)
Date: Thu, 28 Jan 2021 11:32:00 +0000
Subject: [PATCH v4 5/8] block: introduce zone_write_granularity limit
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
 <20210128044733.503606-6-damien.lemoal@wdc.com>
Message-ID: <SN4PR0401MB3598B9246B4F80F2A9A0BCCF9BBA9@SN4PR0401MB3598.namprd04.prod.outlook.com>

Looks good,
Reviewed-by: Johannes Thumshirn <johannes.thumshirn at wdc.com>


From Johannes.Thumshirn at wdc.com  Thu Jan 28 06:33:17 2021
From: Johannes.Thumshirn at wdc.com (Johannes Thumshirn)
Date: Thu, 28 Jan 2021 11:33:17 +0000
Subject: [PATCH v4 6/8] zonefs: use zone write granularity as block size
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
 <20210128044733.503606-7-damien.lemoal@wdc.com>
Message-ID: <SN4PR0401MB35986CEDD79C0EC4746D22E49BBA9@SN4PR0401MB3598.namprd04.prod.outlook.com>

Looks good,
Reviewed-by: Johannes Thumshirn <johanness.thumshirn at wdc.com>


From Johannes.Thumshirn at wdc.com  Thu Jan 28 06:43:52 2021
From: Johannes.Thumshirn at wdc.com (Johannes Thumshirn)
Date: Thu, 28 Jan 2021 11:43:52 +0000
Subject: [PATCH v4 7/8] block: introduce blk_queue_clear_zone_settings()
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
 <20210128044733.503606-8-damien.lemoal@wdc.com>
Message-ID: <SN4PR0401MB35988E69F613B4C91929370A9BBA9@SN4PR0401MB3598.namprd04.prod.outlook.com>

Looks good,
Reviewed-by: Johannes Thumshirn <johannes.thumshirn at wdc.com>


From Johannes.Thumshirn at wdc.com  Thu Jan 28 06:48:15 2021
From: Johannes.Thumshirn at wdc.com (Johannes Thumshirn)
Date: Thu, 28 Jan 2021 11:48:15 +0000
Subject: [PATCH v4 8/8] sd_zbc: clear zone resources for non-zoned case
References: <20210128044733.503606-1-damien.lemoal@wdc.com>
 <20210128044733.503606-9-damien.lemoal@wdc.com>
Message-ID: <SN4PR0401MB359807459C1C4BA9CA43A14A9BBA9@SN4PR0401MB3598.namprd04.prod.outlook.com>

Looks good,
Reviewed-by: Johannes Thumshirn <johannes.thumshirn at edc.com>


From joshiiitr at gmail.com  Thu Jan 28 07:04:47 2021
From: joshiiitr at gmail.com (Kanchan Joshi)
Date: Thu, 28 Jan 2021 17:34:47 +0530
Subject: [RFC PATCH 0/4] Asynchronous passthrough ioctl
In-Reply-To: <a287bd9e-3474-83a4-e5c2-98df17214dc7@gmail.com>
References: <CGME20210127150134epcas5p251fc1de3ff3581dd4c68b3fbe0b9dd91@epcas5p2.samsung.com>
 <20210127150029.13766-1-joshi.k@samsung.com>
 <489691ce-3b1e-30ce-9f72-d32389e33901@gmail.com>
 <a287bd9e-3474-83a4-e5c2-98df17214dc7@gmail.com>
Message-ID: <CA+1E3rJHHFyjwv7Kp32E9H-cf5ksh0pOHSVdGoTpktQrB8SE6A@mail.gmail.com>

On Wed, Jan 27, 2021 at 9:32 PM Pavel Begunkov <asml.silence at gmail.com> wrote:
>
> On 27/01/2021 15:42, Pavel Begunkov wrote:
> > On 27/01/2021 15:00, Kanchan Joshi wrote:
> >> This RFC patchset adds asynchronous ioctl capability for NVMe devices.
> >> Purpose of RFC is to get the feedback and optimize the path.
> >>
> >> At the uppermost io-uring layer, a new opcode IORING_OP_IOCTL_PT is
> >> presented to user-space applications. Like regular-ioctl, it takes
> >> ioctl opcode and an optional argument (ioctl-specific input/output
> >> parameter). Unlike regular-ioctl, it is made to skip the block-layer
> >> and reach directly to the underlying driver (nvme in the case of this
> >> patchset). This path between io-uring and nvme is via a newly
> >> introduced block-device operation "async_ioctl". This operation
> >> expects io-uring to supply a callback function which can be used to
> >> report completion at later stage.
> >>
> >> For a regular ioctl, NVMe driver submits the command to the device and
> >> the submitter (task) is made to wait until completion arrives. For
> >> async-ioctl, completion is decoupled from submission. Submitter goes
> >> back to its business without waiting for nvme-completion. When
> >> nvme-completion arrives, it informs io-uring via the registered
> >> completion-handler. But some ioctls may require updating certain
> >> ioctl-specific fields which can be accessed only in context of the
> >> submitter task. For that reason, NVMe driver uses task-work infra for
> >> that ioctl-specific update. Since task-work is not exported, it cannot
> >> be referenced when nvme is compiled as a module. Therefore, one of the
> >> patch exports task-work API.
> >>
> >> Here goes example of usage (pseudo-code).
> >> Actual nvme-cli source, modified to issue all ioctls via this opcode
> >> is present at-
> >> https://github.com/joshkan/nvme-cli/commit/a008a733f24ab5593e7874cfbc69ee04e88068c5
> >
> > see https://git.kernel.dk/cgit/linux-block/log/?h=io_uring-fops
> >
> > Looks like good time to bring that branch/discussion back
>
> a bit more context:
> https://github.com/axboe/liburing/issues/270

Thanks, it looked good. It seems key differences (compared to
uring-patch that I posted) are -
1. using file-operation instead of block-dev operation.
2. repurpose the sqe memory for ioctl-cmd. If an application does
ioctl with <=40 bytes of cmd, it does not have to allocate ioctl-cmd.
That's nifty. We still need to support passing larger-cmd (e.g.
nvme-passthru ioctl takes 72 bytes) but that shouldn't get too
difficult I suppose.

And for some ioctls, driver may still need to use task-work to update
the user-space pointers (embedded in uring/ioctl cmd) during
completion.

@Jens - will it be fine if I start looking at plumbing nvme-part of
this series on top of your work?


Thanks,


From lkp at intel.com  Thu Jan 28 07:16:58 2021
From: lkp at intel.com (kernel test robot)
Date: Thu, 28 Jan 2021 20:16:58 +0800
Subject: [linux-nvme:nvme-5.11] BUILD SUCCESS
 919a27a9755cc108ff60da3f187f89a64f996320
Message-ID: <6012ab3a.W79lNtyjkbss7TV/%lkp@intel.com>

tree/branch: git://git.infradead.org/nvme.git nvme-5.11
branch HEAD: 919a27a9755cc108ff60da3f187f89a64f996320  nvme-multipath: Early exit if no path is available

elapsed time: 727m

configs tested: 102
configs skipped: 2

The following configs have been built successfully.
More configs may be tested in the coming days.

gcc tested configs:
arm                                 defconfig
arm64                            allyesconfig
arm64                               defconfig
arm                              allyesconfig
arm                              allmodconfig
mips                         rt305x_defconfig
sh                           se7724_defconfig
arm                           u8500_defconfig
h8300                    h8300h-sim_defconfig
mips                      loongson3_defconfig
powerpc                     stx_gp3_defconfig
m68k                        mvme16x_defconfig
sparc                            alldefconfig
arm                        vexpress_defconfig
mips                          rb532_defconfig
um                             i386_defconfig
mips                    maltaup_xpa_defconfig
mips                       bmips_be_defconfig
powerpc                     mpc83xx_defconfig
sh                            migor_defconfig
powerpc                     ppa8548_defconfig
sh                         apsh4a3a_defconfig
arm                       aspeed_g5_defconfig
arm                        mvebu_v5_defconfig
m68k                       m5275evb_defconfig
powerpc                      ppc44x_defconfig
nios2                            allyesconfig
powerpc                  mpc885_ads_defconfig
nios2                         3c120_defconfig
powerpc                 xes_mpc85xx_defconfig
powerpc                 mpc8313_rdb_defconfig
arc                            hsdk_defconfig
mips                        bcm63xx_defconfig
powerpc                    sam440ep_defconfig
arm                           tegra_defconfig
mips                          ath79_defconfig
ia64                             allmodconfig
ia64                                defconfig
ia64                             allyesconfig
m68k                             allmodconfig
m68k                                defconfig
m68k                             allyesconfig
nios2                               defconfig
arc                              allyesconfig
nds32                             allnoconfig
c6x                              allyesconfig
nds32                               defconfig
csky                                defconfig
alpha                               defconfig
alpha                            allyesconfig
xtensa                           allyesconfig
h8300                            allyesconfig
arc                                 defconfig
sh                               allmodconfig
parisc                              defconfig
s390                             allyesconfig
parisc                           allyesconfig
s390                                defconfig
sparc                            allyesconfig
sparc                               defconfig
i386                               tinyconfig
i386                             allyesconfig
i386                                defconfig
mips                             allyesconfig
mips                             allmodconfig
powerpc                          allyesconfig
powerpc                          allmodconfig
powerpc                           allnoconfig
i386                 randconfig-a003-20210128
i386                 randconfig-a006-20210128
x86_64               randconfig-a012-20210128
x86_64               randconfig-a015-20210128
x86_64               randconfig-a016-20210128
x86_64               randconfig-a011-20210128
x86_64               randconfig-a013-20210128
x86_64               randconfig-a014-20210128
i386                 randconfig-a013-20210128
i386                 randconfig-a011-20210128
i386                 randconfig-a012-20210128
i386                 randconfig-a016-20210128
i386                 randconfig-a014-20210128
i386                 randconfig-a015-20210128
riscv                    nommu_k210_defconfig
riscv                            allyesconfig
riscv                    nommu_virt_defconfig
riscv                             allnoconfig
riscv                               defconfig
riscv                          rv32_defconfig
riscv                            allmodconfig
x86_64                                   rhel
x86_64                           allyesconfig
x86_64                    rhel-7.6-kselftests
x86_64                              defconfig
x86_64                               rhel-8.3
x86_64                      rhel-8.3-kbuiltin
x86_64                                  kexec

clang tested configs:
x86_64               randconfig-a002-20210128
x86_64               randconfig-a003-20210128
x86_64               randconfig-a001-20210128
x86_64               randconfig-a005-20210128
x86_64               randconfig-a006-20210128
x86_64               randconfig-a004-20210128

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all at lists.01.org


From lkp at intel.com  Thu Jan 28 07:16:53 2021
From: lkp at intel.com (kernel test robot)
Date: Thu, 28 Jan 2021 20:16:53 +0800
Subject: [linux-nvme:nvme-5.12] BUILD SUCCESS
 ab9dbdb20926f7f2e8387da8e647c7354b8cbb2e
Message-ID: <6012ab35.r66k1TolNyhl6KWb%lkp@intel.com>

tree/branch: git://git.infradead.org/nvme.git nvme-5.12
branch HEAD: ab9dbdb20926f7f2e8387da8e647c7354b8cbb2e  nvme-tcp: use cancel tagset helper for tear down

elapsed time: 727m

configs tested: 94
configs skipped: 2

The following configs have been built successfully.
More configs may be tested in the coming days.

gcc tested configs:
arm                                 defconfig
arm64                            allyesconfig
arm64                               defconfig
arm                              allyesconfig
arm                              allmodconfig
um                             i386_defconfig
mips                    maltaup_xpa_defconfig
mips                       bmips_be_defconfig
powerpc                     mpc83xx_defconfig
sh                            migor_defconfig
powerpc                     ppa8548_defconfig
sh                         apsh4a3a_defconfig
arm                       aspeed_g5_defconfig
arm                        mvebu_v5_defconfig
m68k                       m5275evb_defconfig
powerpc                      ppc44x_defconfig
powerpc                  mpc885_ads_defconfig
nios2                         3c120_defconfig
powerpc                 xes_mpc85xx_defconfig
powerpc                 mpc8313_rdb_defconfig
arc                            hsdk_defconfig
mips                        bcm63xx_defconfig
mips                  cavium_octeon_defconfig
powerpc                  storcenter_defconfig
x86_64                              defconfig
powerpc                    sam440ep_defconfig
arm                           tegra_defconfig
mips                          ath79_defconfig
ia64                             allmodconfig
ia64                                defconfig
ia64                             allyesconfig
m68k                             allmodconfig
m68k                                defconfig
m68k                             allyesconfig
nios2                               defconfig
arc                              allyesconfig
nds32                             allnoconfig
c6x                              allyesconfig
nds32                               defconfig
nios2                            allyesconfig
csky                                defconfig
alpha                               defconfig
alpha                            allyesconfig
xtensa                           allyesconfig
h8300                            allyesconfig
arc                                 defconfig
sh                               allmodconfig
parisc                              defconfig
s390                             allyesconfig
parisc                           allyesconfig
s390                                defconfig
sparc                            allyesconfig
sparc                               defconfig
i386                               tinyconfig
i386                             allyesconfig
i386                                defconfig
mips                             allyesconfig
mips                             allmodconfig
powerpc                          allyesconfig
powerpc                          allmodconfig
powerpc                           allnoconfig
i386                 randconfig-a003-20210128
i386                 randconfig-a006-20210128
x86_64               randconfig-a012-20210128
x86_64               randconfig-a015-20210128
x86_64               randconfig-a016-20210128
x86_64               randconfig-a011-20210128
x86_64               randconfig-a013-20210128
x86_64               randconfig-a014-20210128
i386                 randconfig-a013-20210128
i386                 randconfig-a011-20210128
i386                 randconfig-a012-20210128
i386                 randconfig-a016-20210128
i386                 randconfig-a014-20210128
i386                 randconfig-a015-20210128
riscv                    nommu_k210_defconfig
riscv                            allyesconfig
riscv                    nommu_virt_defconfig
riscv                             allnoconfig
riscv                               defconfig
riscv                          rv32_defconfig
riscv                            allmodconfig
x86_64                                   rhel
x86_64                           allyesconfig
x86_64                    rhel-7.6-kselftests
x86_64                               rhel-8.3
x86_64                      rhel-8.3-kbuiltin
x86_64                                  kexec

clang tested configs:
x86_64               randconfig-a002-20210128
x86_64               randconfig-a003-20210128
x86_64               randconfig-a001-20210128
x86_64               randconfig-a005-20210128
x86_64               randconfig-a006-20210128
x86_64               randconfig-a004-20210128

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all at lists.01.org


From michal.krakowiak at linux.intel.com  Thu Jan 28 07:25:01 2021
From: michal.krakowiak at linux.intel.com (Michal Krakowiak)
Date: Thu, 28 Jan 2021 13:25:01 +0100
Subject: [PATCH] nvme: trace: parse format nvm command in detail
In-Reply-To: <20210127174606.GA28180@lst.de>
References: <20210104155343.GA26034@michal-desk>
 <20210127174606.GA28180@lst.de>
Message-ID: <20210128122501.GA2579222@michal-desk>

Thanks,

I'd like to ask about future nvme tracing development: Will preparing 
similar patches (for more commands) be welcome? I'd like to do it, but I 
got some concerns after the discussion raised due to this patch.


On Wed, Jan 27, 2021 at 06:46:06PM +0100, Christoph Hellwig wrote:
>Thanks,
>
>applied to nvme-5.12.
>


From hch at lst.de  Thu Jan 28 07:39:20 2021
From: hch at lst.de (Christoph Hellwig)
Date: Thu, 28 Jan 2021 13:39:20 +0100
Subject: [PATCH] nvme: trace: parse format nvm command in detail
In-Reply-To: <20210128122501.GA2579222@michal-desk>
References: <20210104155343.GA26034@michal-desk>
 <20210127174606.GA28180@lst.de> <20210128122501.GA2579222@michal-desk>
Message-ID: <20210128123920.GA16013@lst.de>

On Thu, Jan 28, 2021 at 01:25:01PM +0100, Michal Krakowiak wrote:
> Thanks,
>
> I'd like to ask about future nvme tracing development: Will preparing 
> similar patches (for more commands) be welcome? I'd like to do it, but I 
> got some concerns after the discussion raised due to this patch.

I'm a little worried to that we grow decoders for every obscure NVMe
command in the long run.  I think everything that is either issued by
the kernel driver or very commonly used by administrators (e.g. Format
NVM) is a fair game, but at some point we have to draw a line.



From axboe at kernel.dk  Thu Jan 28 09:38:03 2021
From: axboe at kernel.dk (Jens Axboe)
Date: Thu, 28 Jan 2021 07:38:03 -0700
Subject: [RFC PATCH 0/4] Asynchronous passthrough ioctl
In-Reply-To: <CA+1E3rJHHFyjwv7Kp32E9H-cf5ksh0pOHSVdGoTpktQrB8SE6A@mail.gmail.com>
References: <CGME20210127150134epcas5p251fc1de3ff3581dd4c68b3fbe0b9dd91@epcas5p2.samsung.com>
 <20210127150029.13766-1-joshi.k@samsung.com>
 <489691ce-3b1e-30ce-9f72-d32389e33901@gmail.com>
 <a287bd9e-3474-83a4-e5c2-98df17214dc7@gmail.com>
 <CA+1E3rJHHFyjwv7Kp32E9H-cf5ksh0pOHSVdGoTpktQrB8SE6A@mail.gmail.com>
Message-ID: <2d37d0ca-5853-4bb6-1582-551b9044040c@kernel.dk>

On 1/28/21 5:04 AM, Kanchan Joshi wrote:
> On Wed, Jan 27, 2021 at 9:32 PM Pavel Begunkov <asml.silence at gmail.com> wrote:
>>
>> On 27/01/2021 15:42, Pavel Begunkov wrote:
>>> On 27/01/2021 15:00, Kanchan Joshi wrote:
>>>> This RFC patchset adds asynchronous ioctl capability for NVMe devices.
>>>> Purpose of RFC is to get the feedback and optimize the path.
>>>>
>>>> At the uppermost io-uring layer, a new opcode IORING_OP_IOCTL_PT is
>>>> presented to user-space applications. Like regular-ioctl, it takes
>>>> ioctl opcode and an optional argument (ioctl-specific input/output
>>>> parameter). Unlike regular-ioctl, it is made to skip the block-layer
>>>> and reach directly to the underlying driver (nvme in the case of this
>>>> patchset). This path between io-uring and nvme is via a newly
>>>> introduced block-device operation "async_ioctl". This operation
>>>> expects io-uring to supply a callback function which can be used to
>>>> report completion at later stage.
>>>>
>>>> For a regular ioctl, NVMe driver submits the command to the device and
>>>> the submitter (task) is made to wait until completion arrives. For
>>>> async-ioctl, completion is decoupled from submission. Submitter goes
>>>> back to its business without waiting for nvme-completion. When
>>>> nvme-completion arrives, it informs io-uring via the registered
>>>> completion-handler. But some ioctls may require updating certain
>>>> ioctl-specific fields which can be accessed only in context of the
>>>> submitter task. For that reason, NVMe driver uses task-work infra for
>>>> that ioctl-specific update. Since task-work is not exported, it cannot
>>>> be referenced when nvme is compiled as a module. Therefore, one of the
>>>> patch exports task-work API.
>>>>
>>>> Here goes example of usage (pseudo-code).
>>>> Actual nvme-cli source, modified to issue all ioctls via this opcode
>>>> is present at-
>>>> https://github.com/joshkan/nvme-cli/commit/a008a733f24ab5593e7874cfbc69ee04e88068c5
>>>
>>> see https://git.kernel.dk/cgit/linux-block/log/?h=io_uring-fops
>>>
>>> Looks like good time to bring that branch/discussion back
>>
>> a bit more context:
>> https://github.com/axboe/liburing/issues/270
> 
> Thanks, it looked good. It seems key differences (compared to
> uring-patch that I posted) are -
> 1. using file-operation instead of block-dev operation.

Right, it's meant to span wider than just block devices.

> 2. repurpose the sqe memory for ioctl-cmd. If an application does
> ioctl with <=40 bytes of cmd, it does not have to allocate ioctl-cmd.
> That's nifty. We still need to support passing larger-cmd (e.g.
> nvme-passthru ioctl takes 72 bytes) but that shouldn't get too
> difficult I suppose.

It's actually 48 bytes in the as-posted version, and I've bumped it to
56 bytes in the latest branch. So not quite enough for everything,
nothing ever will be, but should work for a lot of cases without
requiring per-command allocations just for the actual command.

> And for some ioctls, driver may still need to use task-work to update
> the user-space pointers (embedded in uring/ioctl cmd) during
> completion.
> 
> @Jens - will it be fine if I start looking at plumbing nvme-part of
> this series on top of your work?

Sure, go ahead. Just beware that things are still changing, so you might
have to adapt it a few times. It's still early days, but I do think
that's the way forward in providing controlled access to what is
basically async ioctls.

-- 
Jens Axboe



From axboe at kernel.dk  Thu Jan 28 09:50:09 2021
From: axboe at kernel.dk (Jens Axboe)
Date: Thu, 28 Jan 2021 07:50:09 -0700
Subject: [RFC PATCH 0/4] Asynchronous passthrough ioctl
In-Reply-To: <CA+1E3rJHHFyjwv7Kp32E9H-cf5ksh0pOHSVdGoTpktQrB8SE6A@mail.gmail.com>
References: <CGME20210127150134epcas5p251fc1de3ff3581dd4c68b3fbe0b9dd91@epcas5p2.samsung.com>
 <20210127150029.13766-1-joshi.k@samsung.com>
 <489691ce-3b1e-30ce-9f72-d32389e33901@gmail.com>
 <a287bd9e-3474-83a4-e5c2-98df17214dc7@gmail.com>
 <CA+1E3rJHHFyjwv7Kp32E9H-cf5ksh0pOHSVdGoTpktQrB8SE6A@mail.gmail.com>
Message-ID: <6d847f4a-65a5-bc62-1d36-52e222e3d142@kernel.dk>

On 1/28/21 5:04 AM, Kanchan Joshi wrote:
> And for some ioctls, driver may still need to use task-work to update
> the user-space pointers (embedded in uring/ioctl cmd) during
> completion.

For this use case, we should ensure that just io_uring handles this
part. It's already got everything setup for it, and I'd rather avoid
having drivers touch any of those parts. Could be done by having an
io_uring helper ala:

io_uring_cmd_complete_in_task(cmd, handler);

which takes care of the nitty gritty details.

-- 
Jens Axboe



From Elad.Grupi at dell.com  Thu Jan 28 10:27:55 2021
From: Elad.Grupi at dell.com (Grupi, Elad)
Date: Thu, 28 Jan 2021 15:27:55 +0000
Subject: [PATCH] nvme-tcp: proper handling of tcp socket closing flows
In-Reply-To: <8eead62d-a96b-46b7-fc87-71e599d3d83d@grimberg.me>
References: <20210126153757.99451-1-elad.grupi@dell.com>
 <8eead62d-a96b-46b7-fc87-71e599d3d83d@grimberg.me>
Message-ID: <DM6PR19MB401119C6C974C85810425C44EFBA9@DM6PR19MB4011.namprd19.prod.outlook.com>

> But we need to call the release_queue work, not sure I understand how this works.

If the tcp socket was closed before setting the socket callback,
nvmet_tcp_set_queue_sock will return -ENOTCONN and everything will be cleared by goto out_destroy_sq.
No need a worker to clean resources in that case and everything is protected by sk_callback_lock.

> io_work is going to run with release_queue_work, because it is also coming from the backend completion. The right way to solve this is to correctly fence them.

> Can you describe the exact race you are referring to?

Correct, the fence already exist in the code, cancel_work_sync is called after nvmet_sq_destroy in release_queue_work. I will remove that part form the patch.

-----Original Message-----
From: Sagi Grimberg <sagi at grimberg.me> 
Sent: Thursday, 28 January 2021 9:55
To: Grupi, Elad; linux-nvme at lists.infradead.org
Subject: Re: [PATCH] nvme-tcp: proper handling of tcp socket closing flows


[EXTERNAL EMAIL] 

> From: Elad Grupi <elad.grupi at dell.com>
> 
> avoid calling nvmet_tcp_release_queue_work if tcp socket was closed 
> before setting the sk callbacks.

But we need to call the release_queue work, not sure I understand how this works.

> 
> prevent io_work from enqueuing while closing the tcp queue to avoid 
> race with nvmet_tcp_release_queue_work.

io_work is going to run with release_queue_work, because it is also coming from the backend completion. The right way to solve this is to correctly fence them.

Can you describe the exact race you are referring to?

> 
> Signed-off-by: Elad Grupi <elad.grupi at dell.com>
> ---
>   drivers/nvme/target/tcp.c | 26 +++++++++++++++++++++-----
>   1 file changed, 21 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c 
> index d535080b781f..937f2a746d8b 100644
> --- a/drivers/nvme/target/tcp.c
> +++ b/drivers/nvme/target/tcp.c
> @@ -647,7 +647,7 @@ static int nvmet_tcp_try_send_one(struct nvmet_tcp_queue *queue,
>   	struct nvmet_tcp_cmd *cmd = queue->snd_cmd;
>   	int ret = 0;
>   
> -	if (!cmd || queue->state == NVMET_TCP_Q_DISCONNECTING) {
> +	if (!cmd) {
>   		cmd = nvmet_tcp_fetch_cmd(queue);
>   		if (unlikely(!cmd))
>   			return 0;
> @@ -1196,7 +1196,7 @@ static void nvmet_tcp_io_work(struct work_struct *w)
>   	/*
>   	 * We exahusted our budget, requeue our selves
>   	 */
> -	if (pending)
> +	if (pending && queue->state != NVMET_TCP_Q_DISCONNECTING)
>   		queue_work_on(queue->cpu, nvmet_tcp_wq, &queue->io_work);
>   }
>   
> @@ -1453,9 +1453,27 @@ static int nvmet_tcp_set_queue_sock(struct nvmet_tcp_queue *queue)
>   	sock->sk->sk_state_change = nvmet_tcp_state_change;
>   	queue->write_space = sock->sk->sk_write_space;
>   	sock->sk->sk_write_space = nvmet_tcp_write_space;
> +
> +	switch (sk->sk_state) {
> +	case TCP_FIN_WAIT1:
> +	case TCP_CLOSE_WAIT:
> +	case TCP_CLOSE:
> +		/* FALLTHRU */
> +		sock->sk->sk_data_ready =  queue->data_ready;
> +		sock->sk->sk_state_change = queue->state_change;
> +		sock->sk->sk_write_space = queue->write_space;
> +		sk->sk_user_data = NULL;
> +		queue->state = NVMET_TCP_Q_DISCONNECTING;
> +		ret = -ENOTCONN;
> +		break;
> +	default:
> +		queue_work_on(queue->cpu, nvmet_tcp_wq, &queue->io_work);
> +		ret = 0;
> +	}
> +
>   	write_unlock_bh(&sock->sk->sk_callback_lock);
>   
> -	return 0;
> +	return ret;
>   }
>   
>   static int nvmet_tcp_alloc_queue(struct nvmet_tcp_port *port, @@ 
> -1506,8 +1524,6 @@ static int nvmet_tcp_alloc_queue(struct nvmet_tcp_port *port,
>   	if (ret)
>   		goto out_destroy_sq;
>   
> -	queue_work_on(queue->cpu, nvmet_tcp_wq, &queue->io_work);
> -
>   	return 0;
>   out_destroy_sq:
>   	mutex_lock(&nvmet_tcp_queue_mutex);
> 

From elad.grupi at dell.com  Thu Jan 28 10:27:58 2021
From: elad.grupi at dell.com (elad.grupi at dell.com)
Date: Thu, 28 Jan 2021 17:27:58 +0200
Subject: [PATCH] nvme-tcp: proper handling of tcp socket closing flows
Message-ID: <20210128152758.114112-1-elad.grupi@dell.com>

From: Elad Grupi <elad.grupi at dell.com>

avoid calling nvmet_tcp_release_queue_work if tcp socket was closed
before setting the sk callbacks.

Signed-off-by: Elad Grupi <elad.grupi at dell.com>
---
 drivers/nvme/target/tcp.c | 24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
index d535080b781f..dac737bac874 100644
--- a/drivers/nvme/target/tcp.c
+++ b/drivers/nvme/target/tcp.c
@@ -647,7 +647,7 @@ static int nvmet_tcp_try_send_one(struct nvmet_tcp_queue *queue,
 	struct nvmet_tcp_cmd *cmd = queue->snd_cmd;
 	int ret = 0;
 
-	if (!cmd || queue->state == NVMET_TCP_Q_DISCONNECTING) {
+	if (!cmd) {
 		cmd = nvmet_tcp_fetch_cmd(queue);
 		if (unlikely(!cmd))
 			return 0;
@@ -1453,9 +1453,27 @@ static int nvmet_tcp_set_queue_sock(struct nvmet_tcp_queue *queue)
 	sock->sk->sk_state_change = nvmet_tcp_state_change;
 	queue->write_space = sock->sk->sk_write_space;
 	sock->sk->sk_write_space = nvmet_tcp_write_space;
+
+	switch (sk->sk_state) {
+	case TCP_FIN_WAIT1:
+	case TCP_CLOSE_WAIT:
+	case TCP_CLOSE:
+		/* FALLTHRU */
+		sock->sk->sk_data_ready =  queue->data_ready;
+		sock->sk->sk_state_change = queue->state_change;
+		sock->sk->sk_write_space = queue->write_space;
+		sk->sk_user_data = NULL;
+		queue->state = NVMET_TCP_Q_DISCONNECTING;
+		ret = -ENOTCONN;
+		break;
+	default:
+		queue_work_on(queue->cpu, nvmet_tcp_wq, &queue->io_work);
+		ret = 0;
+	}
+
 	write_unlock_bh(&sock->sk->sk_callback_lock);
 
-	return 0;
+	return ret;
 }
 
 static int nvmet_tcp_alloc_queue(struct nvmet_tcp_port *port,
@@ -1506,8 +1524,6 @@ static int nvmet_tcp_alloc_queue(struct nvmet_tcp_port *port,
 	if (ret)
 		goto out_destroy_sq;
 
-	queue_work_on(queue->cpu, nvmet_tcp_wq, &queue->io_work);
-
 	return 0;
 out_destroy_sq:
 	mutex_lock(&nvmet_tcp_queue_mutex);
-- 
2.16.5



From joshiiitr at gmail.com  Thu Jan 28 12:13:26 2021
From: joshiiitr at gmail.com (Kanchan Joshi)
Date: Thu, 28 Jan 2021 22:43:26 +0530
Subject: [RFC PATCH 0/4] Asynchronous passthrough ioctl
In-Reply-To: <2d37d0ca-5853-4bb6-1582-551b9044040c@kernel.dk>
References: <CGME20210127150134epcas5p251fc1de3ff3581dd4c68b3fbe0b9dd91@epcas5p2.samsung.com>
 <20210127150029.13766-1-joshi.k@samsung.com>
 <489691ce-3b1e-30ce-9f72-d32389e33901@gmail.com>
 <a287bd9e-3474-83a4-e5c2-98df17214dc7@gmail.com>
 <CA+1E3rJHHFyjwv7Kp32E9H-cf5ksh0pOHSVdGoTpktQrB8SE6A@mail.gmail.com>
 <2d37d0ca-5853-4bb6-1582-551b9044040c@kernel.dk>
Message-ID: <CA+1E3rKeqaLXBuvpMcjZ37XH9RqJHjPnTFObJj0T-u8K9Otw-w@mail.gmail.com>

On Thu, Jan 28, 2021 at 8:08 PM Jens Axboe <axboe at kernel.dk> wrote:
>
> On 1/28/21 5:04 AM, Kanchan Joshi wrote:
> > On Wed, Jan 27, 2021 at 9:32 PM Pavel Begunkov <asml.silence at gmail.com> wrote:
> >>
> >> On 27/01/2021 15:42, Pavel Begunkov wrote:
> >>> On 27/01/2021 15:00, Kanchan Joshi wrote:
> >>>> This RFC patchset adds asynchronous ioctl capability for NVMe devices.
> >>>> Purpose of RFC is to get the feedback and optimize the path.
> >>>>
> >>>> At the uppermost io-uring layer, a new opcode IORING_OP_IOCTL_PT is
> >>>> presented to user-space applications. Like regular-ioctl, it takes
> >>>> ioctl opcode and an optional argument (ioctl-specific input/output
> >>>> parameter). Unlike regular-ioctl, it is made to skip the block-layer
> >>>> and reach directly to the underlying driver (nvme in the case of this
> >>>> patchset). This path between io-uring and nvme is via a newly
> >>>> introduced block-device operation "async_ioctl". This operation
> >>>> expects io-uring to supply a callback function which can be used to
> >>>> report completion at later stage.
> >>>>
> >>>> For a regular ioctl, NVMe driver submits the command to the device and
> >>>> the submitter (task) is made to wait until completion arrives. For
> >>>> async-ioctl, completion is decoupled from submission. Submitter goes
> >>>> back to its business without waiting for nvme-completion. When
> >>>> nvme-completion arrives, it informs io-uring via the registered
> >>>> completion-handler. But some ioctls may require updating certain
> >>>> ioctl-specific fields which can be accessed only in context of the
> >>>> submitter task. For that reason, NVMe driver uses task-work infra for
> >>>> that ioctl-specific update. Since task-work is not exported, it cannot
> >>>> be referenced when nvme is compiled as a module. Therefore, one of the
> >>>> patch exports task-work API.
> >>>>
> >>>> Here goes example of usage (pseudo-code).
> >>>> Actual nvme-cli source, modified to issue all ioctls via this opcode
> >>>> is present at-
> >>>> https://github.com/joshkan/nvme-cli/commit/a008a733f24ab5593e7874cfbc69ee04e88068c5
> >>>
> >>> see https://git.kernel.dk/cgit/linux-block/log/?h=io_uring-fops
> >>>
> >>> Looks like good time to bring that branch/discussion back
> >>
> >> a bit more context:
> >> https://github.com/axboe/liburing/issues/270
> >
> > Thanks, it looked good. It seems key differences (compared to
> > uring-patch that I posted) are -
> > 1. using file-operation instead of block-dev operation.
>
> Right, it's meant to span wider than just block devices.
>
> > 2. repurpose the sqe memory for ioctl-cmd. If an application does
> > ioctl with <=40 bytes of cmd, it does not have to allocate ioctl-cmd.
> > That's nifty. We still need to support passing larger-cmd (e.g.
> > nvme-passthru ioctl takes 72 bytes) but that shouldn't get too
> > difficult I suppose.
>
> It's actually 48 bytes in the as-posted version, and I've bumped it to
> 56 bytes in the latest branch. So not quite enough for everything,
> nothing ever will be, but should work for a lot of cases without
> requiring per-command allocations just for the actual command.

Agreed. But if I got it right, you are open to support both in-the-sqe
command (<= 56 bytes) and out-of-sqe command (> 56 bytes) with this
interface.
Driver processing the ioctl can fetch the cmd from user-space in one
case (as it does now), and skips in another.

> > And for some ioctls, driver may still need to use task-work to update
> > the user-space pointers (embedded in uring/ioctl cmd) during
> > completion.
> >
> > @Jens - will it be fine if I start looking at plumbing nvme-part of
> > this series on top of your work?
>
> Sure, go ahead. Just beware that things are still changing, so you might
> have to adapt it a few times. It's still early days, but I do think
> that's the way forward in providing controlled access to what is
> basically async ioctls.

Sounds good, I will start with the latest branch that you posted. Thanks.

-- 
Kanchan


From konrad.wilk at oracle.com  Thu Jan 28 12:15:28 2021
From: konrad.wilk at oracle.com (Konrad Rzeszutek Wilk)
Date: Thu, 28 Jan 2021 12:15:28 -0500
Subject: [PATCH 2/3] Add swiotlb offset preserving mapping when
 dma_dma_parameters->page_offset_mask is non zero.
In-Reply-To: <20210128003829.1892018-3-jxgao@google.com>
References: <20210128003829.1892018-1-jxgao@google.com>
 <20210128003829.1892018-3-jxgao@google.com>
Message-ID: <YBLxMP3sr71BTL+d@Konrads-MacBook-Pro.local>

On Wed, Jan 27, 2021 at 04:38:28PM -0800, Jianxiong Gao wrote:
> For devices that need to preserve address offset on mapping through
> swiotlb, this patch adds offset preserving based on page_offset_mask
> and keeps the offset if the mask is non zero. This is needed for
> device drivers like NVMe.

<scratches his head>

Didn't you send this patch like a month ago and someone pointed
out that the right fix would be in the NVMe driver?

Is there an issue with fixing the NVMe driver?

> 
> Signed-off-by: Jianxiong Gao <jxgao at google.com>
> ---
>  kernel/dma/swiotlb.c | 25 ++++++++++++++++++++++---
>  1 file changed, 22 insertions(+), 3 deletions(-)
> 
> diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c
> index 7c42df6e6100..4cab35f2c9bc 100644
> --- a/kernel/dma/swiotlb.c
> +++ b/kernel/dma/swiotlb.c
> @@ -468,7 +468,7 @@ phys_addr_t swiotlb_tbl_map_single(struct device *hwdev, phys_addr_t orig_addr,
>  	dma_addr_t tbl_dma_addr = phys_to_dma_unencrypted(hwdev, io_tlb_start);
>  	unsigned long flags;
>  	phys_addr_t tlb_addr;
> -	unsigned int nslots, stride, index, wrap;
> +	unsigned int nslots, stride, index, wrap, page_offset_mask, page_offset;
>  	int i;
>  	unsigned long mask;
>  	unsigned long offset_slots;
> @@ -500,12 +500,16 @@ phys_addr_t swiotlb_tbl_map_single(struct device *hwdev, phys_addr_t orig_addr,
>  		    ? ALIGN(mask + 1, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT
>  		    : 1UL << (BITS_PER_LONG - IO_TLB_SHIFT);
>  
> +	page_offset_mask = dma_get_page_offset_mask(hwdev);
> +	page_offset = orig_addr & page_offset_mask;
> +	alloc_size += page_offset;
> +
>  	/*
>  	 * For mappings greater than or equal to a page, we limit the stride
>  	 * (and hence alignment) to a page size.
>  	 */
>  	nslots = ALIGN(alloc_size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
> -	if (alloc_size >= PAGE_SIZE)
> +	if ((alloc_size >= PAGE_SIZE) || (page_offset_mask > (1 << IO_TLB_SHIFT)))
>  		stride = (1 << (PAGE_SHIFT - IO_TLB_SHIFT));
>  	else
>  		stride = 1;
> @@ -583,6 +587,11 @@ phys_addr_t swiotlb_tbl_map_single(struct device *hwdev, phys_addr_t orig_addr,
>  	 */
>  	for (i = 0; i < nslots; i++)
>  		io_tlb_orig_addr[index+i] = orig_addr + (i << IO_TLB_SHIFT);
> +	/*
> +	 * When keeping the offset of the original data, we need to advance
> +	 * the tlb_addr by the offset of orig_addr.
> +	 */
> +	tlb_addr += page_offset;
>  	if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC) &&
>  	    (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL))
>  		swiotlb_bounce(orig_addr, tlb_addr, mapping_size, DMA_TO_DEVICE);
> @@ -598,7 +607,9 @@ void swiotlb_tbl_unmap_single(struct device *hwdev, phys_addr_t tlb_addr,
>  			      enum dma_data_direction dir, unsigned long attrs)
>  {
>  	unsigned long flags;
> -	int i, count, nslots = ALIGN(alloc_size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
> +	unsigned int num_page_offset_slabs, page_offset_mask = dma_get_page_offset_mask(hwdev);
> +	int i, count;
> +	int nslots = ALIGN(alloc_size + tlb_addr & page_offset_mask, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
>  	int index = (tlb_addr - io_tlb_start) >> IO_TLB_SHIFT;
>  	phys_addr_t orig_addr = io_tlb_orig_addr[index];
>  
> @@ -610,6 +621,14 @@ void swiotlb_tbl_unmap_single(struct device *hwdev, phys_addr_t tlb_addr,
>  	    ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL)))
>  		swiotlb_bounce(orig_addr, tlb_addr, mapping_size, DMA_FROM_DEVICE);
>  
> +	/*
> +	 * When dma_get_page_offset_mask is used, we may have padded more slabs
> +	 * when padding exceeds one slab. We need to move index back to the
> +	 * beginning of the padding.
> +	 */
> +	num_page_offset_slabs =  (tlb_addr & page_offset_mask) / (1 << IO_TLB_SHIFT);
> +	index -= num_page_offset_slabs;
> +
>  	/*
>  	 * Return the buffer to the free list by setting the corresponding
>  	 * entries to indicate the number of contiguous entries available.
> -- 
> 2.27.0
> 


From axboe at kernel.dk  Thu Jan 28 12:24:45 2021
From: axboe at kernel.dk (Jens Axboe)
Date: Thu, 28 Jan 2021 10:24:45 -0700
Subject: [RFC PATCH 0/4] Asynchronous passthrough ioctl
In-Reply-To: <CA+1E3rKeqaLXBuvpMcjZ37XH9RqJHjPnTFObJj0T-u8K9Otw-w@mail.gmail.com>
References: <CGME20210127150134epcas5p251fc1de3ff3581dd4c68b3fbe0b9dd91@epcas5p2.samsung.com>
 <20210127150029.13766-1-joshi.k@samsung.com>
 <489691ce-3b1e-30ce-9f72-d32389e33901@gmail.com>
 <a287bd9e-3474-83a4-e5c2-98df17214dc7@gmail.com>
 <CA+1E3rJHHFyjwv7Kp32E9H-cf5ksh0pOHSVdGoTpktQrB8SE6A@mail.gmail.com>
 <2d37d0ca-5853-4bb6-1582-551b9044040c@kernel.dk>
 <CA+1E3rKeqaLXBuvpMcjZ37XH9RqJHjPnTFObJj0T-u8K9Otw-w@mail.gmail.com>
Message-ID: <dd0392a1-acfa-ef4d-5531-5f1dddc9efe7@kernel.dk>

On 1/28/21 10:13 AM, Kanchan Joshi wrote:
> On Thu, Jan 28, 2021 at 8:08 PM Jens Axboe <axboe at kernel.dk> wrote:
>>
>> On 1/28/21 5:04 AM, Kanchan Joshi wrote:
>>> On Wed, Jan 27, 2021 at 9:32 PM Pavel Begunkov <asml.silence at gmail.com> wrote:
>>>>
>>>> On 27/01/2021 15:42, Pavel Begunkov wrote:
>>>>> On 27/01/2021 15:00, Kanchan Joshi wrote:
>>>>>> This RFC patchset adds asynchronous ioctl capability for NVMe devices.
>>>>>> Purpose of RFC is to get the feedback and optimize the path.
>>>>>>
>>>>>> At the uppermost io-uring layer, a new opcode IORING_OP_IOCTL_PT is
>>>>>> presented to user-space applications. Like regular-ioctl, it takes
>>>>>> ioctl opcode and an optional argument (ioctl-specific input/output
>>>>>> parameter). Unlike regular-ioctl, it is made to skip the block-layer
>>>>>> and reach directly to the underlying driver (nvme in the case of this
>>>>>> patchset). This path between io-uring and nvme is via a newly
>>>>>> introduced block-device operation "async_ioctl". This operation
>>>>>> expects io-uring to supply a callback function which can be used to
>>>>>> report completion at later stage.
>>>>>>
>>>>>> For a regular ioctl, NVMe driver submits the command to the device and
>>>>>> the submitter (task) is made to wait until completion arrives. For
>>>>>> async-ioctl, completion is decoupled from submission. Submitter goes
>>>>>> back to its business without waiting for nvme-completion. When
>>>>>> nvme-completion arrives, it informs io-uring via the registered
>>>>>> completion-handler. But some ioctls may require updating certain
>>>>>> ioctl-specific fields which can be accessed only in context of the
>>>>>> submitter task. For that reason, NVMe driver uses task-work infra for
>>>>>> that ioctl-specific update. Since task-work is not exported, it cannot
>>>>>> be referenced when nvme is compiled as a module. Therefore, one of the
>>>>>> patch exports task-work API.
>>>>>>
>>>>>> Here goes example of usage (pseudo-code).
>>>>>> Actual nvme-cli source, modified to issue all ioctls via this opcode
>>>>>> is present at-
>>>>>> https://github.com/joshkan/nvme-cli/commit/a008a733f24ab5593e7874cfbc69ee04e88068c5
>>>>>
>>>>> see https://git.kernel.dk/cgit/linux-block/log/?h=io_uring-fops
>>>>>
>>>>> Looks like good time to bring that branch/discussion back
>>>>
>>>> a bit more context:
>>>> https://github.com/axboe/liburing/issues/270
>>>
>>> Thanks, it looked good. It seems key differences (compared to
>>> uring-patch that I posted) are -
>>> 1. using file-operation instead of block-dev operation.
>>
>> Right, it's meant to span wider than just block devices.
>>
>>> 2. repurpose the sqe memory for ioctl-cmd. If an application does
>>> ioctl with <=40 bytes of cmd, it does not have to allocate ioctl-cmd.
>>> That's nifty. We still need to support passing larger-cmd (e.g.
>>> nvme-passthru ioctl takes 72 bytes) but that shouldn't get too
>>> difficult I suppose.
>>
>> It's actually 48 bytes in the as-posted version, and I've bumped it to
>> 56 bytes in the latest branch. So not quite enough for everything,
>> nothing ever will be, but should work for a lot of cases without
>> requiring per-command allocations just for the actual command.
> 
> Agreed. But if I got it right, you are open to support both in-the-sqe
> command (<= 56 bytes) and out-of-sqe command (> 56 bytes) with this
> interface.
> Driver processing the ioctl can fetch the cmd from user-space in one
> case (as it does now), and skips in another.

Your out-of-seq command would be none of io_urings business, outside of
the fact that we'd need to ensure it's stable if we need to postpone
it. So yes, that would be fine, it just means your actual command is
passed in as a pointer, and you would be responsible for copying it
in for execution

We're going to need something to handle postponing, and something
for ensuring that eg cancelations free the allocated memory.

>>> And for some ioctls, driver may still need to use task-work to update
>>> the user-space pointers (embedded in uring/ioctl cmd) during
>>> completion.
>>>
>>> @Jens - will it be fine if I start looking at plumbing nvme-part of
>>> this series on top of your work?
>>
>> Sure, go ahead. Just beware that things are still changing, so you might
>> have to adapt it a few times. It's still early days, but I do think
>> that's the way forward in providing controlled access to what is
>> basically async ioctls.
> 
> Sounds good, I will start with the latest branch that you posted. Thanks.

It's io_uring-fops.v2 for now, use that one.

-- 
Jens Axboe



From joshiiitr at gmail.com  Thu Jan 28 12:25:41 2021
From: joshiiitr at gmail.com (Kanchan Joshi)
Date: Thu, 28 Jan 2021 22:55:41 +0530
Subject: [RFC PATCH 0/4] Asynchronous passthrough ioctl
In-Reply-To: <6d847f4a-65a5-bc62-1d36-52e222e3d142@kernel.dk>
References: <CGME20210127150134epcas5p251fc1de3ff3581dd4c68b3fbe0b9dd91@epcas5p2.samsung.com>
 <20210127150029.13766-1-joshi.k@samsung.com>
 <489691ce-3b1e-30ce-9f72-d32389e33901@gmail.com>
 <a287bd9e-3474-83a4-e5c2-98df17214dc7@gmail.com>
 <CA+1E3rJHHFyjwv7Kp32E9H-cf5ksh0pOHSVdGoTpktQrB8SE6A@mail.gmail.com>
 <6d847f4a-65a5-bc62-1d36-52e222e3d142@kernel.dk>
Message-ID: <CA+1E3rLD2e4yFsA-gxPGtp2Fg2Z0sdfpS3Rz+WsUC4i5aF43LA@mail.gmail.com>

On Thu, Jan 28, 2021 at 8:20 PM Jens Axboe <axboe at kernel.dk> wrote:
>
> On 1/28/21 5:04 AM, Kanchan Joshi wrote:
> > And for some ioctls, driver may still need to use task-work to update
> > the user-space pointers (embedded in uring/ioctl cmd) during
> > completion.
>
> For this use case, we should ensure that just io_uring handles this
> part. It's already got everything setup for it, and I'd rather avoid
> having drivers touch any of those parts. Could be done by having an
> io_uring helper ala:
>
> io_uring_cmd_complete_in_task(cmd, handler);
>
> which takes care of the nitty gritty details.

Ah right. With that, I can do away with exporting task-work.
NVMe completion can invoke (depending on ioctl) this uring-helper with
a handler that does the ioctl-specific update in task context.



-- 
Kanchan


From robin.murphy at arm.com  Thu Jan 28 12:27:25 2021
From: robin.murphy at arm.com (Robin Murphy)
Date: Thu, 28 Jan 2021 17:27:25 +0000
Subject: [PATCH 1/3] Adding page_offset_mask to device_dma_parameters
In-Reply-To: <20210128003829.1892018-2-jxgao@google.com>
References: <20210128003829.1892018-1-jxgao@google.com>
 <20210128003829.1892018-2-jxgao@google.com>
Message-ID: <2863b6d2-47f6-51fa-f60c-ba24904818e9@arm.com>

On 2021-01-28 00:38, Jianxiong Gao wrote:
> Some devices rely on the address offset in a page to function
> correctly (NVMe driver as an example). These devices may use
> a different page size than the Linux kernel. The address offset
> has to be preserved upon mapping, and in order to do so, we
> need to record the page_offset_mask first.
> 
> Signed-off-by: Jianxiong Gao <jxgao at google.com>
> ---
>   include/linux/device.h      |  1 +
>   include/linux/dma-mapping.h | 17 +++++++++++++++++
>   2 files changed, 18 insertions(+)
> 
> diff --git a/include/linux/device.h b/include/linux/device.h
> index 1779f90eeb4c..f44e0659fc66 100644
> --- a/include/linux/device.h
> +++ b/include/linux/device.h
> @@ -292,6 +292,7 @@ struct device_dma_parameters {
>   	 */
>   	unsigned int max_segment_size;
>   	unsigned long segment_boundary_mask;
> +	unsigned int page_offset_mask;

Could we call this something more like "min_align_mask" (sorry, I can't 
think of a name that's actually good and descriptive right now). 
Essentially I worry that having "page" in there is going to be too easy 
to misinterpret as having anything to do what "page" means almost 
everywhere else (even before you throw IOMMU pages into the mix).

Also note that of all the possible ways to pack two ints and a long, 
this one is the worst ;)

Robin.

>   };
>   
>   /**
> diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
> index 2e49996a8f39..5529a31fefba 100644
> --- a/include/linux/dma-mapping.h
> +++ b/include/linux/dma-mapping.h
> @@ -500,6 +500,23 @@ static inline int dma_set_seg_boundary(struct device *dev, unsigned long mask)
>   	return -EIO;
>   }
>   
> +static inline unsigned int dma_get_page_offset_mask(struct device *dev)
> +{
> +	if (dev->dma_parms)
> +		return dev->dma_parms->page_offset_mask;
> +	return 0;
> +}
> +
> +static inline int dma_set_page_offset_mask(struct device *dev,
> +		unsigned int page_offset_mask)
> +{
> +	if (dev->dma_parms) {
> +		dev->dma_parms->page_offset_mask = page_offset_mask;
> +		return 0;
> +	}
> +	return -EIO;
> +}
> +
>   static inline int dma_get_cache_alignment(void)
>   {
>   #ifdef ARCH_DMA_MINALIGN
> 


From kbusch at kernel.org  Thu Jan 28 12:34:51 2021
From: kbusch at kernel.org (Keith Busch)
Date: Fri, 29 Jan 2021 02:34:51 +0900
Subject: [PATCH 2/3] Add swiotlb offset preserving mapping when
 dma_dma_parameters->page_offset_mask is non zero.
In-Reply-To: <YBLxMP3sr71BTL+d@Konrads-MacBook-Pro.local>
References: <20210128003829.1892018-1-jxgao@google.com>
 <20210128003829.1892018-3-jxgao@google.com>
 <YBLxMP3sr71BTL+d@Konrads-MacBook-Pro.local>
Message-ID: <20210128173451.GA31631@redsun51.ssa.fujisawa.hgst.com>

On Thu, Jan 28, 2021 at 12:15:28PM -0500, Konrad Rzeszutek Wilk wrote:
> On Wed, Jan 27, 2021 at 04:38:28PM -0800, Jianxiong Gao wrote:
> > For devices that need to preserve address offset on mapping through
> > swiotlb, this patch adds offset preserving based on page_offset_mask
> > and keeps the offset if the mask is non zero. This is needed for
> > device drivers like NVMe.
> 
> <scratches his head>
> 
> Didn't you send this patch like a month ago and someone pointed
> out that the right fix would be in the NVMe driver?
> 
> Is there an issue with fixing the NVMe driver?

You got it backwards. The initial "fix" used a flag specific to the nvme
driver, and it was pointed out that it should just be the generic
behaviour.


From robin.murphy at arm.com  Thu Jan 28 13:00:58 2021
From: robin.murphy at arm.com (Robin Murphy)
Date: Thu, 28 Jan 2021 18:00:58 +0000
Subject: [PATCH 3/3] Adding device_dma_parameters->offset_preserve_mask to
 NVMe driver.
In-Reply-To: <20210128003829.1892018-4-jxgao@google.com>
References: <20210128003829.1892018-1-jxgao@google.com>
 <20210128003829.1892018-4-jxgao@google.com>
Message-ID: <0550ca25-1389-ffc2-e738-8127ceb1712f@arm.com>

On 2021-01-28 00:38, Jianxiong Gao wrote:
> NVMe driver relies on the address offset to function properly.
> This patch adds the offset preserve mask to NVMe driver when mapping
> via dma_map_sg_attrs and unmapping via nvme_unmap_sg. The mask
> depends on the page size defined by CC.MPS register of NVMe
> controller.
> 
> Signed-off-by: Jianxiong Gao <jxgao at google.com>
> ---
>   drivers/nvme/host/pci.c | 19 +++++++++++++++++--
>   1 file changed, 17 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
> index 856aa31931c1..0b23f04068be 100644
> --- a/drivers/nvme/host/pci.c
> +++ b/drivers/nvme/host/pci.c
> @@ -580,12 +580,15 @@ static void nvme_free_sgls(struct nvme_dev *dev, struct request *req)
>   static void nvme_unmap_sg(struct nvme_dev *dev, struct request *req)
>   {
>   	struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
> -
> +	if (dma_set_page_offset_mask(dev->dev, NVME_CTRL_PAGE_SIZE - 1))
> +		dev_warn(dev->dev, "dma_set_page_offset_mask failed to set offset\n");
>   	if (is_pci_p2pdma_page(sg_page(iod->sg)))
>   		pci_p2pdma_unmap_sg(dev->dev, iod->sg, iod->nents,
>   				    rq_dma_dir(req));
>   	else
>   		dma_unmap_sg(dev->dev, iod->sg, iod->nents, rq_dma_dir(req));
> +	if (dma_set_page_offset_mask(dev->dev, 0))
> +		dev_warn(dev->dev, "dma_set_page_offset_mask failed to reset offset\n");
>   }
>   
>   static void nvme_unmap_data(struct nvme_dev *dev, struct request *req)
> @@ -842,7 +845,7 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
>   {
>   	struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
>   	blk_status_t ret = BLK_STS_RESOURCE;
> -	int nr_mapped;
> +	int nr_mapped, offset_ret;
>   
>   	if (blk_rq_nr_phys_segments(req) == 1) {
>   		struct bio_vec bv = req_bvec(req);
> @@ -868,12 +871,24 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
>   	if (!iod->nents)
>   		goto out_free_sg;
>   
> +	offset_ret = dma_set_page_offset_mask(dev->dev, NVME_CTRL_PAGE_SIZE - 1);
> +	if (offset_ret) {
> +		dev_warn(dev->dev, "dma_set_page_offset_mask failed to set offset\n");
> +		goto out_free_sg;
> +	}
> +
>   	if (is_pci_p2pdma_page(sg_page(iod->sg)))
>   		nr_mapped = pci_p2pdma_map_sg_attrs(dev->dev, iod->sg,
>   				iod->nents, rq_dma_dir(req), DMA_ATTR_NO_WARN);
>   	else
>   		nr_mapped = dma_map_sg_attrs(dev->dev, iod->sg, iod->nents,
>   					     rq_dma_dir(req), DMA_ATTR_NO_WARN);
> +
> +	offset_ret = dma_set_page_offset_mask(dev->dev, 0);
> +	if (offset_ret) {
> +		dev_warn(dev->dev, "dma_set_page_offset_mask failed to reset offset\n");
> +		goto out_free_sg;

If it were possible for this to fail, you might leak the DMA mapping 
here. However if dev->dma_parms somehow disappeared since a dozen lines 
above then I think you've got far bigger problems anyway.

That said, do you really need to keep toggling this back and forth all 
the time? Even if the device does make other mappings elsewhere that 
don't necessarily need the same strict alignment, would it be 
significantly harmful just to set it once at probe and leave it in place 
anyway?

Robin.

> +	}
>   	if (!nr_mapped)
>   		goto out_free_sg;
>   
> 


From hch at lst.de  Thu Jan 28 13:15:57 2021
From: hch at lst.de (Christoph Hellwig)
Date: Thu, 28 Jan 2021 19:15:57 +0100
Subject: [PATCH 1/3] Adding page_offset_mask to device_dma_parameters
In-Reply-To: <2863b6d2-47f6-51fa-f60c-ba24904818e9@arm.com>
References: <20210128003829.1892018-1-jxgao@google.com>
 <20210128003829.1892018-2-jxgao@google.com>
 <2863b6d2-47f6-51fa-f60c-ba24904818e9@arm.com>
Message-ID: <20210128181557.GA11790@lst.de>

On Thu, Jan 28, 2021 at 05:27:25PM +0000, Robin Murphy wrote:
> On 2021-01-28 00:38, Jianxiong Gao wrote:
>> Some devices rely on the address offset in a page to function
>> correctly (NVMe driver as an example). These devices may use
>> a different page size than the Linux kernel. The address offset
>> has to be preserved upon mapping, and in order to do so, we
>> need to record the page_offset_mask first.
>>
>> Signed-off-by: Jianxiong Gao <jxgao at google.com>
>> ---
>>   include/linux/device.h      |  1 +
>>   include/linux/dma-mapping.h | 17 +++++++++++++++++
>>   2 files changed, 18 insertions(+)
>>
>> diff --git a/include/linux/device.h b/include/linux/device.h
>> index 1779f90eeb4c..f44e0659fc66 100644
>> --- a/include/linux/device.h
>> +++ b/include/linux/device.h
>> @@ -292,6 +292,7 @@ struct device_dma_parameters {
>>   	 */
>>   	unsigned int max_segment_size;
>>   	unsigned long segment_boundary_mask;
>> +	unsigned int page_offset_mask;
>
> Could we call this something more like "min_align_mask" (sorry, I can't 
> think of a name that's actually good and descriptive right now). 
> Essentially I worry that having "page" in there is going to be too easy to 
> misinterpret as having anything to do what "page" means almost everywhere 
> else (even before you throw IOMMU pages into the mix).
>
> Also note that of all the possible ways to pack two ints and a long, this 
> one is the worst ;)

The block layer uses virt_boundary for the related concept, but that
is pretty horrible too.


From hch at lst.de  Thu Jan 28 13:16:27 2021
From: hch at lst.de (Christoph Hellwig)
Date: Thu, 28 Jan 2021 19:16:27 +0100
Subject: [PATCH 2/3] Add swiotlb offset preserving mapping when
 dma_dma_parameters->page_offset_mask is non zero.
In-Reply-To: <20210128003829.1892018-3-jxgao@google.com>
References: <20210128003829.1892018-1-jxgao@google.com>
 <20210128003829.1892018-3-jxgao@google.com>
Message-ID: <20210128181627.GB11790@lst.de>

On Wed, Jan 27, 2021 at 04:38:28PM -0800, Jianxiong Gao wrote:
> For devices that need to preserve address offset on mapping through
> swiotlb, this patch adds offset preserving based on page_offset_mask
> and keeps the offset if the mask is non zero. This is needed for
> device drivers like NVMe.
> 
> Signed-off-by: Jianxiong Gao <jxgao at google.com>
> ---
>  kernel/dma/swiotlb.c | 25 ++++++++++++++++++++++---
>  1 file changed, 22 insertions(+), 3 deletions(-)
> 
> diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c
> index 7c42df6e6100..4cab35f2c9bc 100644
> --- a/kernel/dma/swiotlb.c
> +++ b/kernel/dma/swiotlb.c
> @@ -468,7 +468,7 @@ phys_addr_t swiotlb_tbl_map_single(struct device *hwdev, phys_addr_t orig_addr,
>  	dma_addr_t tbl_dma_addr = phys_to_dma_unencrypted(hwdev, io_tlb_start);
>  	unsigned long flags;
>  	phys_addr_t tlb_addr;
> -	unsigned int nslots, stride, index, wrap;
> +	unsigned int nslots, stride, index, wrap, page_offset_mask, page_offset;
>  	int i;
>  	unsigned long mask;
>  	unsigned long offset_slots;
> @@ -500,12 +500,16 @@ phys_addr_t swiotlb_tbl_map_single(struct device *hwdev, phys_addr_t orig_addr,
>  		    ? ALIGN(mask + 1, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT
>  		    : 1UL << (BITS_PER_LONG - IO_TLB_SHIFT);
>  
> +	page_offset_mask = dma_get_page_offset_mask(hwdev);
> +	page_offset = orig_addr & page_offset_mask;
> +	alloc_size += page_offset;
> +
>  	/*
>  	 * For mappings greater than or equal to a page, we limit the stride
>  	 * (and hence alignment) to a page size.
>  	 */
>  	nslots = ALIGN(alloc_size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
> -	if (alloc_size >= PAGE_SIZE)
> +	if ((alloc_size >= PAGE_SIZE) || (page_offset_mask > (1 << IO_TLB_SHIFT)))
>  		stride = (1 << (PAGE_SHIFT - IO_TLB_SHIFT));
>  	else
>  		stride = 1;
> @@ -583,6 +587,11 @@ phys_addr_t swiotlb_tbl_map_single(struct device *hwdev, phys_addr_t orig_addr,
>  	 */
>  	for (i = 0; i < nslots; i++)
>  		io_tlb_orig_addr[index+i] = orig_addr + (i << IO_TLB_SHIFT);
> +	/*
> +	 * When keeping the offset of the original data, we need to advance
> +	 * the tlb_addr by the offset of orig_addr.
> +	 */
> +	tlb_addr += page_offset;
>  	if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC) &&
>  	    (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL))
>  		swiotlb_bounce(orig_addr, tlb_addr, mapping_size, DMA_TO_DEVICE);
> @@ -598,7 +607,9 @@ void swiotlb_tbl_unmap_single(struct device *hwdev, phys_addr_t tlb_addr,
>  			      enum dma_data_direction dir, unsigned long attrs)
>  {
>  	unsigned long flags;
> -	int i, count, nslots = ALIGN(alloc_size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
> +	unsigned int num_page_offset_slabs, page_offset_mask = dma_get_page_offset_mask(hwdev);

Yikes, please avoid these crazy long lines.

> +	num_page_offset_slabs =  (tlb_addr & page_offset_mask) / (1 << IO_TLB_SHIFT);

also a double whitespace here.


From hch at lst.de  Thu Jan 28 13:18:04 2021
From: hch at lst.de (Christoph Hellwig)
Date: Thu, 28 Jan 2021 19:18:04 +0100
Subject: [PATCH 3/3] Adding device_dma_parameters->offset_preserve_mask
 to NVMe driver.
In-Reply-To: <0550ca25-1389-ffc2-e738-8127ceb1712f@arm.com>
References: <20210128003829.1892018-1-jxgao@google.com>
 <20210128003829.1892018-4-jxgao@google.com>
 <0550ca25-1389-ffc2-e738-8127ceb1712f@arm.com>
Message-ID: <20210128181804.GC11790@lst.de>

On Thu, Jan 28, 2021 at 06:00:58PM +0000, Robin Murphy wrote:
> If it were possible for this to fail, you might leak the DMA mapping here. 
> However if dev->dma_parms somehow disappeared since a dozen lines above 
> then I think you've got far bigger problems anyway.
>
> That said, do you really need to keep toggling this back and forth all the 
> time? Even if the device does make other mappings elsewhere that don't 
> necessarily need the same strict alignment, would it be significantly 
> harmful just to set it once at probe and leave it in place anyway?

Yes, we should kept it set all the time.  While some NVMe devices have
the optional to use SGLs that do not have this limitation, I have
absolutely no sympathy for anyone running NVMe with swiotlb as that
means their system imposes an addressing limitation.  We need to make
sure it does not corrupt data, but we're not going to make any effort
to optimize for such a degenerated setup.


From hch at lst.de  Thu Jan 28 13:25:24 2021
From: hch at lst.de (Christoph Hellwig)
Date: Thu, 28 Jan 2021 19:25:24 +0100
Subject: [PATCH] nvme-core: use list_add_tail_rcu instead of
 list_add_tail for nvme_init_ns_head
In-Reply-To: <20210128033351.22116-1-lengchao@huawei.com>
References: <20210128033351.22116-1-lengchao@huawei.com>
Message-ID: <20210128182524.GA12912@lst.de>

Thanks,

applied to nvme-5.11.


From hch at infradead.org  Thu Jan 28 13:56:50 2021
From: hch at infradead.org (Christoph Hellwig)
Date: Thu, 28 Jan 2021 19:56:50 +0100
Subject: [GIT PULL] nvme fixes for 5.11
Message-ID: <YBMI8qpv8l/vKOlx@infradead.org>

The following changes since commit 8dc932d3e8afb65e12eba7495f046c83884c49bf:

  Revert "block: simplify set_init_blocksize" to regain lost performance (2021-01-27 09:14:12 -0700)

are available in the Git repository at:

  git://git.infradead.org/nvme.git tags/nvme-5.11-2021-01-28

for you to fetch changes up to 772ea326a4a00b6b4b2c8f3606ad10c31f46c511:

  nvme-core: use list_add_tail_rcu instead of list_add_tail for nvme_init_ns_head (2021-01-28 19:25:07 +0100)

----------------------------------------------------------------
nvme fixes for 5.11:

 - add another Write Zeroes quirk (Chaitanya Kulkarni)
 - handle a no path available corner case (Daniel Wagner)
 - use the proper RCU aware list_add helper (Chao Leng)

----------------------------------------------------------------
Chaitanya Kulkarni (1):
      nvme-pci: add the DISABLE_WRITE_ZEROES quirk for a SPCC device

Chao Leng (1):
      nvme-core: use list_add_tail_rcu instead of list_add_tail for nvme_init_ns_head

Daniel Wagner (1):
      nvme-multipath: Early exit if no path is available

 drivers/nvme/host/core.c      | 2 +-
 drivers/nvme/host/multipath.c | 2 +-
 drivers/nvme/host/pci.c       | 2 ++
 3 files changed, 4 insertions(+), 2 deletions(-)


From axboe at kernel.dk  Thu Jan 28 13:58:05 2021
From: axboe at kernel.dk (Jens Axboe)
Date: Thu, 28 Jan 2021 11:58:05 -0700
Subject: [GIT PULL] nvme fixes for 5.11
In-Reply-To: <YBMI8qpv8l/vKOlx@infradead.org>
References: <YBMI8qpv8l/vKOlx@infradead.org>
Message-ID: <ec942804-628f-83c4-6cbd-5c1a9ada6e13@kernel.dk>

On 1/28/21 11:56 AM, Christoph Hellwig wrote:
> git://git.infradead.org/nvme.git tags/nvme-5.11-2021-01-28

Pulled, thanks.

-- 
Jens Axboe



From sagi at grimberg.me  Thu Jan 28 17:03:15 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Thu, 28 Jan 2021 14:03:15 -0800
Subject: [PATCH] nvme-tcp: proper handling of tcp socket closing flows
In-Reply-To: <20210128152758.114112-1-elad.grupi@dell.com>
References: <20210128152758.114112-1-elad.grupi@dell.com>
Message-ID: <2c2a3aa6-ca43-e9b0-7928-28c6962ea1bc@grimberg.me>


> ---
>   drivers/nvme/target/tcp.c | 24 ++++++++++++++++++++----
>   1 file changed, 20 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
> index d535080b781f..dac737bac874 100644
> --- a/drivers/nvme/target/tcp.c
> +++ b/drivers/nvme/target/tcp.c
> @@ -647,7 +647,7 @@ static int nvmet_tcp_try_send_one(struct nvmet_tcp_queue *queue,
>   	struct nvmet_tcp_cmd *cmd = queue->snd_cmd;
>   	int ret = 0;
>   
> -	if (!cmd || queue->state == NVMET_TCP_Q_DISCONNECTING) {
> +	if (!cmd) {
>   		cmd = nvmet_tcp_fetch_cmd(queue);
>   		if (unlikely(!cmd))
>   			return 0;
> @@ -1453,9 +1453,27 @@ static int nvmet_tcp_set_queue_sock(struct nvmet_tcp_queue *queue)
>   	sock->sk->sk_state_change = nvmet_tcp_state_change;
>   	queue->write_space = sock->sk->sk_write_space;
>   	sock->sk->sk_write_space = nvmet_tcp_write_space;
> +
> +	switch (sk->sk_state) {
> +	case TCP_FIN_WAIT1:
> +	case TCP_CLOSE_WAIT:
> +	case TCP_CLOSE:
> +		/* FALLTHRU */
> +		sock->sk->sk_data_ready =  queue->data_ready;
> +		sock->sk->sk_state_change = queue->state_change;
> +		sock->sk->sk_write_space = queue->write_space;
> +		sk->sk_user_data = NULL;
> +		queue->state = NVMET_TCP_Q_DISCONNECTING;
> +		ret = -ENOTCONN;
> +		break;
> +	default:
> +		queue_work_on(queue->cpu, nvmet_tcp_wq, &queue->io_work);
> +		ret = 0;
> +	}
> +
>   	write_unlock_bh(&sock->sk->sk_callback_lock);
>   
> -	return 0;
> +	return ret;
>   }
>   
>   static int nvmet_tcp_alloc_queue(struct nvmet_tcp_port *port,
> @@ -1506,8 +1524,6 @@ static int nvmet_tcp_alloc_queue(struct nvmet_tcp_port *port,
>   	if (ret)
>   		goto out_destroy_sq;
>   
> -	queue_work_on(queue->cpu, nvmet_tcp_wq, &queue->io_work);
> -
>   	return 0;
>   out_destroy_sq:
>   	mutex_lock(&nvmet_tcp_queue_mutex);
> 


What about this instead?
--
diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
index c41902f7ce39..6388d18ca7c2 100644
--- a/drivers/nvme/target/tcp.c
+++ b/drivers/nvme/target/tcp.c
@@ -1494,16 +1494,28 @@ static int nvmet_tcp_set_queue_sock(struct 
nvmet_tcp_queue *queue)
                 ip_sock_set_tos(sock->sk, inet->rcv_tos);

         write_lock_bh(&sock->sk->sk_callback_lock);
-       sock->sk->sk_user_data = queue;
-       queue->data_ready = sock->sk->sk_data_ready;
-       sock->sk->sk_data_ready = nvmet_tcp_data_ready;
-       queue->state_change = sock->sk->sk_state_change;
-       sock->sk->sk_state_change = nvmet_tcp_state_change;
-       queue->write_space = sock->sk->sk_write_space;
-       sock->sk->sk_write_space = nvmet_tcp_write_space;
+       switch (sk->sk_state) {
+       case TCP_FIN_WAIT1:
+       case TCP_CLOSE_WAIT:
+       case TCP_CLOSE:
+               /*
+                * If the socket is already closing, don't even start
+                * consuming it
+                */
+               ret = -ENOTCONN;
+               break;
+       default:
+               sock->sk->sk_user_data = queue;
+               queue->data_ready = sock->sk->sk_data_ready;
+               sock->sk->sk_data_ready = nvmet_tcp_data_ready;
+               queue->state_change = sock->sk->sk_state_change;
+               sock->sk->sk_state_change = nvmet_tcp_state_change;
+               queue->write_space = sock->sk->sk_write_space;
+               sock->sk->sk_write_space = nvmet_tcp_write_space;
+       }
         write_unlock_bh(&sock->sk->sk_callback_lock);

-       return 0;
+       return ret;
  }
--


From Elad.Grupi at dell.com  Thu Jan 28 18:07:12 2021
From: Elad.Grupi at dell.com (Grupi, Elad)
Date: Thu, 28 Jan 2021 23:07:12 +0000
Subject: [PATCH] nvme-tcp: proper handling of tcp socket closing flows
In-Reply-To: <2c2a3aa6-ca43-e9b0-7928-28c6962ea1bc@grimberg.me>
References: <20210128152758.114112-1-elad.grupi@dell.com>
 <2c2a3aa6-ca43-e9b0-7928-28c6962ea1bc@grimberg.me>
Message-ID: <DM6PR19MB40113530FCB4DF6F52E8C752EFBA9@DM6PR19MB4011.namprd19.prod.outlook.com>

That will work if sk_state_change is called under sk_callback_lock.

In addition, need to flush_work(&queue->port->accept_work) in nvmet_tcp_release_queue_work because accept_work is still using queue struct after unlocking sk_callback_lock.


-----Original Message-----
From: Sagi Grimberg <sagi at grimberg.me> 
Sent: Friday, 29 January 2021 0:03
To: Grupi, Elad; linux-nvme at lists.infradead.org
Subject: Re: [PATCH] nvme-tcp: proper handling of tcp socket closing flows


[EXTERNAL EMAIL] 


> ---
>   drivers/nvme/target/tcp.c | 24 ++++++++++++++++++++----
>   1 file changed, 20 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c 
> index d535080b781f..dac737bac874 100644
> --- a/drivers/nvme/target/tcp.c
> +++ b/drivers/nvme/target/tcp.c
> @@ -647,7 +647,7 @@ static int nvmet_tcp_try_send_one(struct nvmet_tcp_queue *queue,
>   	struct nvmet_tcp_cmd *cmd = queue->snd_cmd;
>   	int ret = 0;
>   
> -	if (!cmd || queue->state == NVMET_TCP_Q_DISCONNECTING) {
> +	if (!cmd) {
>   		cmd = nvmet_tcp_fetch_cmd(queue);
>   		if (unlikely(!cmd))
>   			return 0;
> @@ -1453,9 +1453,27 @@ static int nvmet_tcp_set_queue_sock(struct nvmet_tcp_queue *queue)
>   	sock->sk->sk_state_change = nvmet_tcp_state_change;
>   	queue->write_space = sock->sk->sk_write_space;
>   	sock->sk->sk_write_space = nvmet_tcp_write_space;
> +
> +	switch (sk->sk_state) {
> +	case TCP_FIN_WAIT1:
> +	case TCP_CLOSE_WAIT:
> +	case TCP_CLOSE:
> +		/* FALLTHRU */
> +		sock->sk->sk_data_ready =  queue->data_ready;
> +		sock->sk->sk_state_change = queue->state_change;
> +		sock->sk->sk_write_space = queue->write_space;
> +		sk->sk_user_data = NULL;
> +		queue->state = NVMET_TCP_Q_DISCONNECTING;
> +		ret = -ENOTCONN;
> +		break;
> +	default:
> +		queue_work_on(queue->cpu, nvmet_tcp_wq, &queue->io_work);
> +		ret = 0;
> +	}
> +
>   	write_unlock_bh(&sock->sk->sk_callback_lock);
>   
> -	return 0;
> +	return ret;
>   }
>   
>   static int nvmet_tcp_alloc_queue(struct nvmet_tcp_port *port, @@ 
> -1506,8 +1524,6 @@ static int nvmet_tcp_alloc_queue(struct nvmet_tcp_port *port,
>   	if (ret)
>   		goto out_destroy_sq;
>   
> -	queue_work_on(queue->cpu, nvmet_tcp_wq, &queue->io_work);
> -
>   	return 0;
>   out_destroy_sq:
>   	mutex_lock(&nvmet_tcp_queue_mutex);
> 


What about this instead?
--
diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c index c41902f7ce39..6388d18ca7c2 100644
--- a/drivers/nvme/target/tcp.c
+++ b/drivers/nvme/target/tcp.c
@@ -1494,16 +1494,28 @@ static int nvmet_tcp_set_queue_sock(struct nvmet_tcp_queue *queue)
                 ip_sock_set_tos(sock->sk, inet->rcv_tos);

         write_lock_bh(&sock->sk->sk_callback_lock);
-       sock->sk->sk_user_data = queue;
-       queue->data_ready = sock->sk->sk_data_ready;
-       sock->sk->sk_data_ready = nvmet_tcp_data_ready;
-       queue->state_change = sock->sk->sk_state_change;
-       sock->sk->sk_state_change = nvmet_tcp_state_change;
-       queue->write_space = sock->sk->sk_write_space;
-       sock->sk->sk_write_space = nvmet_tcp_write_space;
+       switch (sk->sk_state) {
+       case TCP_FIN_WAIT1:
+       case TCP_CLOSE_WAIT:
+       case TCP_CLOSE:
+               /*
+                * If the socket is already closing, don't even start
+                * consuming it
+                */
+               ret = -ENOTCONN;
+               break;
+       default:
+               sock->sk->sk_user_data = queue;
+               queue->data_ready = sock->sk->sk_data_ready;
+               sock->sk->sk_data_ready = nvmet_tcp_data_ready;
+               queue->state_change = sock->sk->sk_state_change;
+               sock->sk->sk_state_change = nvmet_tcp_state_change;
+               queue->write_space = sock->sk->sk_write_space;
+               sock->sk->sk_write_space = nvmet_tcp_write_space;
+       }
         write_unlock_bh(&sock->sk->sk_callback_lock);

-       return 0;
+       return ret;
  }
--

From sagi at grimberg.me  Thu Jan 28 18:33:46 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Thu, 28 Jan 2021 15:33:46 -0800
Subject: [PATCH] nvme-tcp: proper handling of tcp socket closing flows
In-Reply-To: <DM6PR19MB40113530FCB4DF6F52E8C752EFBA9@DM6PR19MB4011.namprd19.prod.outlook.com>
References: <20210128152758.114112-1-elad.grupi@dell.com>
 <2c2a3aa6-ca43-e9b0-7928-28c6962ea1bc@grimberg.me>
 <DM6PR19MB40113530FCB4DF6F52E8C752EFBA9@DM6PR19MB4011.namprd19.prod.outlook.com>
Message-ID: <9d974783-dc05-61b1-902e-a0cbe13199f0@grimberg.me>


> That will work if sk_state_change is called under sk_callback_lock.

It is.

> In addition, need to flush_work(&queue->port->accept_work) in nvmet_tcp_release_queue_work because accept_work is still using queue struct after unlocking sk_callback_lock.


But sk->sk_user_data was not set, so I don't see how the release work
can invoke.

> What about this instead?
> --
> diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c index c41902f7ce39..6388d18ca7c2 100644
> --- a/drivers/nvme/target/tcp.c
> +++ b/drivers/nvme/target/tcp.c
> @@ -1494,16 +1494,28 @@ static int nvmet_tcp_set_queue_sock(struct nvmet_tcp_queue *queue)
>                   ip_sock_set_tos(sock->sk, inet->rcv_tos);
> 
>           write_lock_bh(&sock->sk->sk_callback_lock);
> -       sock->sk->sk_user_data = queue;
> -       queue->data_ready = sock->sk->sk_data_ready;
> -       sock->sk->sk_data_ready = nvmet_tcp_data_ready;
> -       queue->state_change = sock->sk->sk_state_change;
> -       sock->sk->sk_state_change = nvmet_tcp_state_change;
> -       queue->write_space = sock->sk->sk_write_space;
> -       sock->sk->sk_write_space = nvmet_tcp_write_space;
> +       switch (sk->sk_state) {
> +       case TCP_FIN_WAIT1:
> +       case TCP_CLOSE_WAIT:
> +       case TCP_CLOSE:
> +               /*
> +                * If the socket is already closing, don't even start
> +                * consuming it
> +                */
> +               ret = -ENOTCONN;
> +               break;
> +       default:
> +               sock->sk->sk_user_data = queue;
> +               queue->data_ready = sock->sk->sk_data_ready;
> +               sock->sk->sk_data_ready = nvmet_tcp_data_ready;
> +               queue->state_change = sock->sk->sk_state_change;
> +               sock->sk->sk_state_change = nvmet_tcp_state_change;
> +               queue->write_space = sock->sk->sk_write_space;
> +               sock->sk->sk_write_space = nvmet_tcp_write_space;
> +       }
>           write_unlock_bh(&sock->sk->sk_callback_lock);
> 
> -       return 0;
> +       return ret;
>    }
> --
> 


From Elad.Grupi at dell.com  Thu Jan 28 18:43:14 2021
From: Elad.Grupi at dell.com (Grupi, Elad)
Date: Thu, 28 Jan 2021 23:43:14 +0000
Subject: [PATCH] nvme-tcp: proper handling of tcp socket closing flows
In-Reply-To: <9d974783-dc05-61b1-902e-a0cbe13199f0@grimberg.me>
References: <20210128152758.114112-1-elad.grupi@dell.com>
 <2c2a3aa6-ca43-e9b0-7928-28c6962ea1bc@grimberg.me>
 <DM6PR19MB40113530FCB4DF6F52E8C752EFBA9@DM6PR19MB4011.namprd19.prod.outlook.com>
 <9d974783-dc05-61b1-902e-a0cbe13199f0@grimberg.me>
Message-ID: <DM6PR19MB401116F68376949D24B6803AEFBA9@DM6PR19MB4011.namprd19.prod.outlook.com>

Release work might get invoked if nvmet_tcp_set_queue_sock is completed successfully and set sk_user_data, but sk_state_change is triggered by network stack before queue_work_on is invoked. That case - there is a race between release_work and accept_work.

-----Original Message-----
From: Sagi Grimberg <sagi at grimberg.me> 
Sent: Friday, 29 January 2021 1:34
To: Grupi, Elad; linux-nvme at lists.infradead.org
Subject: Re: [PATCH] nvme-tcp: proper handling of tcp socket closing flows


[EXTERNAL EMAIL] 


> That will work if sk_state_change is called under sk_callback_lock.

It is.

> In addition, need to flush_work(&queue->port->accept_work) in nvmet_tcp_release_queue_work because accept_work is still using queue struct after unlocking sk_callback_lock.


But sk->sk_user_data was not set, so I don't see how the release work can invoke.

> What about this instead?
> --
> diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c 
> index c41902f7ce39..6388d18ca7c2 100644
> --- a/drivers/nvme/target/tcp.c
> +++ b/drivers/nvme/target/tcp.c
> @@ -1494,16 +1494,28 @@ static int nvmet_tcp_set_queue_sock(struct nvmet_tcp_queue *queue)
>                   ip_sock_set_tos(sock->sk, inet->rcv_tos);
> 
>           write_lock_bh(&sock->sk->sk_callback_lock);
> -       sock->sk->sk_user_data = queue;
> -       queue->data_ready = sock->sk->sk_data_ready;
> -       sock->sk->sk_data_ready = nvmet_tcp_data_ready;
> -       queue->state_change = sock->sk->sk_state_change;
> -       sock->sk->sk_state_change = nvmet_tcp_state_change;
> -       queue->write_space = sock->sk->sk_write_space;
> -       sock->sk->sk_write_space = nvmet_tcp_write_space;
> +       switch (sk->sk_state) {
> +       case TCP_FIN_WAIT1:
> +       case TCP_CLOSE_WAIT:
> +       case TCP_CLOSE:
> +               /*
> +                * If the socket is already closing, don't even start
> +                * consuming it
> +                */
> +               ret = -ENOTCONN;
> +               break;
> +       default:
> +               sock->sk->sk_user_data = queue;
> +               queue->data_ready = sock->sk->sk_data_ready;
> +               sock->sk->sk_data_ready = nvmet_tcp_data_ready;
> +               queue->state_change = sock->sk->sk_state_change;
> +               sock->sk->sk_state_change = nvmet_tcp_state_change;
> +               queue->write_space = sock->sk->sk_write_space;
> +               sock->sk->sk_write_space = nvmet_tcp_write_space;
> +       }
>           write_unlock_bh(&sock->sk->sk_callback_lock);
> 
> -       return 0;
> +       return ret;
>    }
> --
> 

From sagi at grimberg.me  Thu Jan 28 18:54:06 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Thu, 28 Jan 2021 15:54:06 -0800
Subject: [PATCH] nvme-tcp: proper handling of tcp socket closing flows
In-Reply-To: <DM6PR19MB401116F68376949D24B6803AEFBA9@DM6PR19MB4011.namprd19.prod.outlook.com>
References: <20210128152758.114112-1-elad.grupi@dell.com>
 <2c2a3aa6-ca43-e9b0-7928-28c6962ea1bc@grimberg.me>
 <DM6PR19MB40113530FCB4DF6F52E8C752EFBA9@DM6PR19MB4011.namprd19.prod.outlook.com>
 <9d974783-dc05-61b1-902e-a0cbe13199f0@grimberg.me>
 <DM6PR19MB401116F68376949D24B6803AEFBA9@DM6PR19MB4011.namprd19.prod.outlook.com>
Message-ID: <53c6c0f6-99f7-ca1b-c205-05f7a03c1785@grimberg.me>


> Release work might get invoked if nvmet_tcp_set_queue_sock is completed successfully and set sk_user_data, but sk_state_change is triggered by network stack before queue_work_on is invoked. That case - there is a race between release_work and accept_work.

This is just like any other case where release_work races with io_work.
That is not an exception from other cases which release_work will need
to fence from.


From Elad.Grupi at dell.com  Thu Jan 28 19:01:34 2021
From: Elad.Grupi at dell.com (Grupi, Elad)
Date: Fri, 29 Jan 2021 00:01:34 +0000
Subject: [PATCH] nvme-tcp: proper handling of tcp socket closing flows
In-Reply-To: <53c6c0f6-99f7-ca1b-c205-05f7a03c1785@grimberg.me>
References: <20210128152758.114112-1-elad.grupi@dell.com>
 <2c2a3aa6-ca43-e9b0-7928-28c6962ea1bc@grimberg.me>
 <DM6PR19MB40113530FCB4DF6F52E8C752EFBA9@DM6PR19MB4011.namprd19.prod.outlook.com>
 <9d974783-dc05-61b1-902e-a0cbe13199f0@grimberg.me>
 <DM6PR19MB401116F68376949D24B6803AEFBA9@DM6PR19MB4011.namprd19.prod.outlook.com>
 <53c6c0f6-99f7-ca1b-c205-05f7a03c1785@grimberg.me>
Message-ID: <DM6PR19MB4011CDB6E299B8EB3F25AC0AEFB99@DM6PR19MB4011.namprd19.prod.outlook.com>

That's not what I meant.

My concern is release_work races with accept_work.

nvmet_tcp_alloc_queue is called from accept_work context and still accessing the queue struct after setting sk callbacks.

-----Original Message-----
From: Sagi Grimberg <sagi at grimberg.me> 
Sent: Friday, 29 January 2021 1:54
To: Grupi, Elad; linux-nvme at lists.infradead.org
Subject: Re: [PATCH] nvme-tcp: proper handling of tcp socket closing flows


[EXTERNAL EMAIL] 


> Release work might get invoked if nvmet_tcp_set_queue_sock is completed successfully and set sk_user_data, but sk_state_change is triggered by network stack before queue_work_on is invoked. That case - there is a race between release_work and accept_work.

This is just like any other case where release_work races with io_work.
That is not an exception from other cases which release_work will need to fence from.

From sagi at grimberg.me  Thu Jan 28 19:07:20 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Thu, 28 Jan 2021 16:07:20 -0800
Subject: [PATCH] nvme-tcp: proper handling of tcp socket closing flows
In-Reply-To: <DM6PR19MB4011CDB6E299B8EB3F25AC0AEFB99@DM6PR19MB4011.namprd19.prod.outlook.com>
References: <20210128152758.114112-1-elad.grupi@dell.com>
 <2c2a3aa6-ca43-e9b0-7928-28c6962ea1bc@grimberg.me>
 <DM6PR19MB40113530FCB4DF6F52E8C752EFBA9@DM6PR19MB4011.namprd19.prod.outlook.com>
 <9d974783-dc05-61b1-902e-a0cbe13199f0@grimberg.me>
 <DM6PR19MB401116F68376949D24B6803AEFBA9@DM6PR19MB4011.namprd19.prod.outlook.com>
 <53c6c0f6-99f7-ca1b-c205-05f7a03c1785@grimberg.me>
 <DM6PR19MB4011CDB6E299B8EB3F25AC0AEFB99@DM6PR19MB4011.namprd19.prod.outlook.com>
Message-ID: <7d9dca89-c57d-73f3-aacd-97262f6b27ad@grimberg.me>


> That's not what I meant.
> 
> My concern is release_work races with accept_work.
> 
> nvmet_tcp_alloc_queue is called from accept_work context and still accessing the queue struct after setting sk callbacks.

I see, we can move the queue_work to set_queue_sock then.


From sagi at grimberg.me  Thu Jan 28 20:14:23 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Thu, 28 Jan 2021 17:14:23 -0800
Subject: [PATCH 00/35] RFC: add "nvme monitor" subcommand
In-Reply-To: <20210126203324.23610-1-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
Message-ID: <60846bb5-c0df-ac23-260b-b53afd48f661@grimberg.me>


> From: Martin Wilck <mwilck at suse.com>
> 
> (Cover letter copied from https://github.com/linux-nvme/nvme-cli/pull/877)
> 
> This patch set adds a new subcommand **nvme monitor**. In this mode,
> **nvme-cli** runs continuously, monitors events (currently, uevents) relevant
> for discovery, and optionally autoconnects to newly discovered subsystems.
> 
> The monitor mode is suitable to be run in a systemd service. An appropriate
> unit file is provided. As such, **nvme monitor** can be used as an alternative
> to the current auto-connection mechanism based on udev rules and systemd
> template units. If `--autoconnect` is active, **nvme monitor** masks the
> respective udev rules in order to prevent simultaneous connection attempts
> from udev and itself.

I think that a monitor daemon is a good path forward.

> 
> This method for discovery and autodetection has some advantages over the
> current udev-rule based approach:
> 
>   * By using the `--persistent` option, users can easily control whether
>     persistent discovery controllers for discovered transport addresses should
>     be created and monitored for AEN events. **nvme monitor** watches known
>     transport addresses, creates discovery controllers as required, and re-uses
>     existing ones if possible.

What does that mean?

  It keeps track of persistent discovery
>     controllers it created, and tears them down on exit. When run in
>     `--persistent --autoconnect` mode *in the initial ramfs*, it will keep
>     discovery controllers alive, so that a new instance started after switching
>     root can simply re-use them.

Nice.

>   * In certain situations, the systemd-based approach may miss events due to
>     race conditions. This can happen e.g. if an FC remote port is detected, but
>     shortly after it's detection an FC relogin procedure is necessary e.g. due to
>     an RSCN. In this case, an `fc_udev_device` uevent will be received on the
>     first detection and handled by an `nvme connect-all` command run from
>     `nvmf-connect at .service`. The connection attempt to the rport in question will
>     fail with "no such device" because of the simultaneous FC
>     relogin. `nvmf-connect at .service` may not terminate immediately, because it
>     attempts to establish other connections listed in the Discovery Log page it
>     retrieved. When the FC relogin eventually finishes, a new uevent will be
>     received, and `nvmf-connect@` will be started again, but *this has no effect*
>     if the previous `nvmf-connect@` service hasn't finished yet. This is the
>     general semantics of systemd services, no easy workaround exists.  **nvme
>     monitor** doesn't suffer from this problem. If it sees an uevent for a
>     transport address for which a discovery is already running, it will queue the
>     handling of this event up and restart the discovery after it's finished.

While I understand the issue, this reason alone is an overkill for doing 
this.

>   * Resource consumption for handling uevents is lower. Instead of running an
>     udev worker, executing the rules, executing `systemctl start` from the
>     worker, starting a systemd service, and starting a separate **nvme-cli**
>     instance, only a single `fork()` operation is necessary. Of course, on the
>     back side, the monitor itself consumes resources while it's running and
>     waiting for events. On my system with 8 persistent discovery controllers,
>     its RSS is ~3MB. CPU consumption is zero as long as no events occur.

What is the baseline with what we have today?

>   * **nvme monitor** could be easily extended to handle events for non-FC
>     transports.

Which events?

> 
> I've tested `fc_udev_device` handling for NVMeoFC with an Ontap target, and
> AEN handling for RDMA using a Linux **nvmet** target.
> 
> ### Implementation notes
> 
> I've tried to change the exisiting **nvme-cli** code as little as possible
> while reusing the code from `fabrics.c`. The majority of changes in the
> existing code exports formerly static functions and variables, so that they
> are usable from the monitor code.

General comment, can you please separate out fixes/cleanups that are not
related to the goal of this patchset?

> 
> The main process just waits for events using `epoll()`. When an event is
> received that necessitates a new discovery, a child is forked. This makes it
> possible to fill in the configuration parameters for `do_discover()` without
> interfering with the main process or other discovery tasks running in
> parallel. The program tracks *transport addresses* (called "connections" in
> the code) rather than NVMe controllers. In `--persistent` mode, it tries to
> maintain exactly one persistent discovery connection per transport address.
> 
> Using `epoll()` may look over-engineered at this stage. I hope the better
> flexibility over `poll()` (in particular, the ability to add new event sources
> while waiting) will simplify future extensions and improvements.
> 
> ### Todo
> 
>   * Referrals are not handled perfectly yet. They will be handled by
>     `do_discover()` just as it would when called from **nvme connect-all**, but
>     it would be better to pass referrals back to the main process to make it
>     aware of the additional discovery controller rather than using
>     recursion. The main process would e.g. know if a discovery is already
>     running for the transport address in the referrral.

Agree, this way you can also keep new referrals persistently, which I
don't know if we do today.

>   *  When "add" uevents for nvme controller devices are received, the
>      controller is consistently not in `live` state yet, and attempting to read
>      the `subsysnqn` sysfs attribute returns `(efault)`. While this should
>      arguably be fixed in the kernel, it could be worked around in user space
>      by using timers or polling the `state` sysfs attribute for changes.

This is a bug, what in the code causes this? nothing in controller state
should prevent from this sysfs read from executing correctly...

>   * Parse and handle `discovery.conf` on startup.

This is a must I think, where do you get the known transport addresses
on startup today?

>   * Implement support for RDMA and TCP protocols.

What is needed for supporting them? Not sure I follow (I thought
you mentioned that you tested against linux nvmet-rdma?)


From lengchao at huawei.com  Thu Jan 28 20:18:10 2021
From: lengchao at huawei.com (Chao Leng)
Date: Fri, 29 Jan 2021 09:18:10 +0800
Subject: [PATCH v2] nvme-multipath: Early exit if no path is available
In-Reply-To: <8704038d-0b71-5c9c-2d2b-a9ff2166dbe4@suse.de>
References: <20210127103033.15318-1-dwagner@suse.de>
 <db9baae0-547c-7ff4-8b2c-0b95f14be67c@huawei.com>
 <20210128075837.u5u56t23fq5gu6ou@beryllium.lan>
 <69575290-200e-b4a1-4269-c71e4c2cc37b@huawei.com>
 <8704038d-0b71-5c9c-2d2b-a9ff2166dbe4@suse.de>
Message-ID: <c91cb4df-6736-bc0f-9d33-ecc3e2f4f510@huawei.com>



On 2021/1/28 17:23, Hannes Reinecke wrote:
> On 1/28/21 10:18 AM, Chao Leng wrote:
>>
>>
>> On 2021/1/28 15:58, Daniel Wagner wrote:
>>> On Thu, Jan 28, 2021 at 09:31:30AM +0800, Chao Leng wrote:
>>>>> --- a/drivers/nvme/host/multipath.c
>>>>> +++ b/drivers/nvme/host/multipath.c
>>>>> @@ -221,7 +221,7 @@ static struct nvme_ns *nvme_round_robin_path(struct nvme_ns_head *head,
>>>>> ?????? }
>>>>> ?????? for (ns = nvme_next_ns(head, old);
>>>>> -???????? ns != old;
>>>>> +???????? ns && ns != old;
>>>> nvme_round_robin_path just be called when !"old".
>>>> nvme_next_ns should not return NULL when !"old".
>>>> It seems unnecessary to add checking "ns".
>>>
>>> The problem is when we enter nvme_round_robin_path() and there is no
>>> path available. In this case the initialization ns = nvme_next_ns(head,
>>> old) could return a NULL pointer."old" should not be NULL, so there is at least one path that is "old".
>> It is impossible to return NULL for nvme_next_ns(head, old).
> 
> No. list_next_or_null_rcu()/list_first_or_null_rcu() will return NULL when then end of the list is reached.
Although list_next_or_null_rcu()/list_first_or_null_rcu() may return
NULL, but nvme_next_ns(head, old) assume that the "old" is in the "head",
so nvme_next_ns(head, old) should not return NULL. If the "old" is not
in the "head", nvme_next_ns(head, old) will run abnormal.
So there is other bug which cause nvme_next_ns(head, old).

I review the code about head->list and head->current_path, I find 2 bugs
may cause nvme_next_ns(head, old) abnormal:
First, I already send the patch. see:
https://lore.kernel.org/linux-nvme/20210128033351.22116-1-lengchao at huawei.com/
Second, in nvme_ns_remove, list_del_rcu is before
nvme_mpath_clear_current_path. This may cause "old" is deleted from the
"head", but still use "old". I'm not sure there's any other
consideration here, I will check it and try to fix it.
> 
> Cheers,
> 
> Hannes


From lengchao at huawei.com  Thu Jan 28 20:23:31 2021
From: lengchao at huawei.com (Chao Leng)
Date: Fri, 29 Jan 2021 09:23:31 +0800
Subject: [PATCH v2] nvme-multipath: Early exit if no path is available
In-Reply-To: <20210128094004.erwnszjqcxlsi2kd@beryllium.lan>
References: <20210127103033.15318-1-dwagner@suse.de>
 <db9baae0-547c-7ff4-8b2c-0b95f14be67c@huawei.com>
 <20210128075837.u5u56t23fq5gu6ou@beryllium.lan>
 <69575290-200e-b4a1-4269-c71e4c2cc37b@huawei.com>
 <20210128094004.erwnszjqcxlsi2kd@beryllium.lan>
Message-ID: <ebb1d098-3ded-e592-4419-e905aabe824f@huawei.com>



On 2021/1/28 17:40, Daniel Wagner wrote:
> On Thu, Jan 28, 2021 at 05:18:56PM +0800, Chao Leng wrote:
>> It is impossible to return NULL for nvme_next_ns(head, old).
> 
>   block nvme0n1: no usable path - requeuing I/O
>   block nvme0n1: no usable path - requeuing I/O
>   block nvme0n1: no usable path - requeuing I/O
>   block nvme0n1: no usable path - requeuing I/O
>   block nvme0n1: no usable path - requeuing I/O
>   block nvme0n1: no usable path - requeuing I/O
>   BUG: kernel NULL pointer dereference, address: 0000000000000068
>   #PF: supervisor read access in kernel mode
>   #PF: error_code(0x0000) - not-present page
>   PGD 8000000ff67bc067 P4D 8000000ff67bc067 PUD ff9ac9067 PMD 0
>   Oops: 0000 [#1] SMP PTI
>   CPU: 23 PID: 15759 Comm: dt.21.15 Kdump: loaded Tainted: G            E       5.3.18-0.gc9fe679-default #1 SLE15-SP2 (unreleased)
>   Hardware name: FUJITSU PRIMERGY RX2540 M2/D3289-B1, BIOS V5.0.0.11 R1.18.0 for D3289-B1x                    02/06/2018
>   RIP: 0010:nvme_ns_head_make_request+0x1d1/0x430 [nvme_core]
>   Code: 54 24 10 0f 84 c9 01 00 00 48 8b 54 24 10 48 83 ea 30 0f 84 ba 01 00 00 48 39 d0 0f 84 01 02 00 00 31 ff eb 05 48 39 d0 74 67 <48> 8b 72 68 83 e6 04 75 13 48 8b 72 68 83 e6 01 75 0a 48 8b 72 10
>   RSP: 0018:ffffa69d08017af8 EFLAGS: 00010246
>   RAX: ffff92f261d87800 RBX: ffff92fa555b0010 RCX: ffff92fa555bc570
>   RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
>   RBP: 0000000000000001 R08: 0000000000001000 R09: 0000000000001000
>   R10: ffffa69d080179a8 R11: ffff92f264f0c1c0 R12: ffff92f264f7f000
>   R13: ffff92fa555b0000 R14: 0000000000000001 R15: 0000000000000000
>   FS:  00007f3962bae700(0000) GS:ffff92f29ffc0000(0000) knlGS:0000000000000000
>   CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>   CR2: 0000000000000068 CR3: 0000000fd69a2002 CR4: 00000000003606e0
>   DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
>   DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
>   Call Trace:
>    generic_make_request+0x121/0x300
>    ? submit_bio+0x42/0x1c0
>    submit_bio+0x42/0x1c0
>    ext4_io_submit+0x49/0x60 [ext4]
>    ext4_writepages+0x625/0xe90 [ext4]
>    ? do_writepages+0x4b/0xe0
>    ? ext4_mark_inode_dirty+0x1d0/0x1d0 [ext4]
>    do_writepages+0x4b/0xe0
>    ? __generic_file_write_iter+0x192/0x1c0
>    ? __filemap_fdatawrite_range+0xcb/0x100
>    __filemap_fdatawrite_range+0xcb/0x100
>    ? ext4_file_write_iter+0x128/0x3c0 [ext4]
>    file_write_and_wait_range+0x5e/0xb0
>    __generic_file_fsync+0x22/0xb0
>    ext4_sync_file+0x1f7/0x3c0 [ext4]
>    do_fsync+0x38/0x60
>    __x64_sys_fsync+0x10/0x20
>    do_syscall_64+0x5b/0x1e0
> entry_SYSCALL_64_after_hwframe+0x44/0xa9
> 
> You can't see exactly where it dies but I followed the assembly to
> nvme_round_robin_path(). Maybe it's not the initial nvme_next_ns(head,
> old) which returns NULL but nvme_next_ns() is returning NULL eventually
> (list_next_or_null_rcu()).
So there is other bug cause nvme_next_ns abormal.
I review the code about head->list and head->current_path, I find 2 bugs
may cause the bug:
First, I already send the patch. see:
https://lore.kernel.org/linux-nvme/20210128033351.22116-1-lengchao at huawei.com/
Second, in nvme_ns_remove, list_del_rcu is before
nvme_mpath_clear_current_path. This may cause "old" is deleted from the
"head", but still use "old". I'm not sure there's any other
consideration here, I will check it and try to fix it.
> 
> And I have positive feedback, this patch fixes the above problem.
Although adding check ns can fix the crash. There may still be other problems
such as in __nvme_find_path which use list_for_each_entry_rcu.
> 
> .
> 


From sagi at grimberg.me  Thu Jan 28 20:35:40 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Thu, 28 Jan 2021 17:35:40 -0800
Subject: [PATCH v4 4/5] nvme-rdma: avoid IO error for nvme native multipath
In-Reply-To: <9c30b18a-6fdd-be1c-f3bc-1d44c35ae274@huawei.com>
References: <20210126081539.13320-1-lengchao@huawei.com>
 <20210126081539.13320-5-lengchao@huawei.com>
 <5a368693-65fd-1bdf-924a-f90df7f59b2a@grimberg.me>
 <9c30b18a-6fdd-be1c-f3bc-1d44c35ae274@huawei.com>
Message-ID: <ca300cac-1f6c-01b2-8691-9a545381523a@grimberg.me>


>>> @@ -2084,8 +2085,10 @@ static blk_status_t nvme_rdma_queue_rq(struct 
>>> blk_mq_hw_ctx *hctx,
>>> ????? err = nvme_rdma_post_send(queue, sqe, req->sge, req->num_sge,
>>> ????????????? req->mr ? &req->reg_wr.wr : NULL);
>>> -??? if (unlikely(err))
>>> +??? if (unlikely(err)) {
>>> +??????? driver_error = true;
>>> ????????? goto err_unmap;
>>
>> Why not just call set the status and call nvme_rdma_complete_rq and
>> return here?
> If the err is ENOMEM or EAGAIN, I am not sure the err must be a
> path-related error for all HBA drivers. So reused the error check code.
> I think it would be more reasonable to assume any errors returned by HBA
> driver as path-related errors.
> If you think so, I will modify it in next patch version.

Meant to do that only for -EIO. We should absolutely not do any of this
for stuff like EINVAL, EOPNOTSUPP, EPERM or any strange error that may
return due to a bug or anything like that.


From sagi at grimberg.me  Thu Jan 28 20:42:34 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Thu, 28 Jan 2021 17:42:34 -0800
Subject: [PATCH v2] nvme-multipath: Early exit if no path is available
In-Reply-To: <ebb1d098-3ded-e592-4419-e905aabe824f@huawei.com>
References: <20210127103033.15318-1-dwagner@suse.de>
 <db9baae0-547c-7ff4-8b2c-0b95f14be67c@huawei.com>
 <20210128075837.u5u56t23fq5gu6ou@beryllium.lan>
 <69575290-200e-b4a1-4269-c71e4c2cc37b@huawei.com>
 <20210128094004.erwnszjqcxlsi2kd@beryllium.lan>
 <ebb1d098-3ded-e592-4419-e905aabe824f@huawei.com>
Message-ID: <675d3cf7-1ae8-adc5-b6d0-359fe10f6b23@grimberg.me>


>> You can't see exactly where it dies but I followed the assembly to
>> nvme_round_robin_path(). Maybe it's not the initial nvme_next_ns(head,
>> old) which returns NULL but nvme_next_ns() is returning NULL eventually
>> (list_next_or_null_rcu()).
> So there is other bug cause nvme_next_ns abormal.
> I review the code about head->list and head->current_path, I find 2 bugs
> may cause the bug:
> First, I already send the patch. see:
> https://lore.kernel.org/linux-nvme/20210128033351.22116-1-lengchao at huawei.com/ 
> 
> Second, in nvme_ns_remove, list_del_rcu is before
> nvme_mpath_clear_current_path. This may cause "old" is deleted from the
> "head", but still use "old". I'm not sure there's any other
> consideration here, I will check it and try to fix it.

The reason why we first remove from head->list and only then clear
current_path is because the other way around there is no way
to guarantee that that the ns won't be assigned as current_path
again (because it is in head->list).

nvme_ns_remove fences continue of deletion of the ns by synchronizing
the srcu such that for sure the current_path clearance is visible.


From sagi at grimberg.me  Thu Jan 28 20:52:22 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Thu, 28 Jan 2021 17:52:22 -0800
Subject: [PATCH 13/35] monitor: disable nvmf-autoconnect udev rules in
 autoconnect mode
In-Reply-To: <20210126203324.23610-14-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-14-mwilck@suse.com>
Message-ID: <8990bb65-fb2d-7ab1-82cd-210c4c4dba13@grimberg.me>



On 1/26/21 12:33 PM, mwilck at suse.com wrote:
> From: Martin Wilck <mwilck at suse.com>
> 
> If autoconnect is enabled, disable the respective udev rules
> by symlinking /run/udev/rules.d to /dev/null, in order to avoid
> the connections being set up by the monitor and the udev workers
> at the same time. This is probably the preferred mode of operation
> for the monitor.
> 
> Users can override this by copying 70-nvmf-autoconnect.rules
> from /usr/lib/udev/rules.d to /etc/udev/rules.d (/etc/udev/rules.d
> takes precedence over /run/udev/rules.d).
> 
> If the symlink can't be created for some reason, autoconnect will
> be disabled. There is  only one exception: If
> /run/udev/rules.d/70-nvmf-autoconnect.rules already points to
> /dev/null at startup, autoconnect can be left on, but the symlink
> isn't removed on exit.

Can't we just document that just one should be enabled and skip
the entire thing? Especially when its not critical if both run..


From sagi at grimberg.me  Thu Jan 28 20:54:22 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Thu, 28 Jan 2021 17:54:22 -0800
Subject: [PATCH 16/35] monitor: reset children's signal disposition
In-Reply-To: <20210126203324.23610-17-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-17-mwilck@suse.com>
Message-ID: <35ef1b10-1d24-f0f3-3af8-2d14d710533c@grimberg.me>

No commit message?

> 
> Signed-off-by: Martin Wilck <mwilck at suse.com>
> ---
>   monitor.c | 30 ++++++++++++++++++++++++++++--
>   1 file changed, 28 insertions(+), 2 deletions(-)
> 
> diff --git a/monitor.c b/monitor.c
> index 69c8333..9375a14 100644
> --- a/monitor.c
> +++ b/monitor.c
> @@ -100,6 +100,8 @@ static void monitor_int_handler(int sig)
>   	must_exit = 1;
>   }
>   
> +static sigset_t orig_sigmask;
> +
>   static int monitor_init_signals(void)
>   {
>   	sigset_t mask;
> @@ -110,7 +112,7 @@ static int monitor_init_signals(void)
>   	 * for events.
>   	 */
>   	sigfillset(&mask);
> -	if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
> +	if (sigprocmask(SIG_BLOCK, &mask, &orig_sigmask) == -1)
>   		return -errno;
>   	if (sigaction(SIGTERM, &sa, NULL) == -1)
>   		return -errno;
> @@ -119,6 +121,26 @@ static int monitor_init_signals(void)
>   	return 0;
>   }
>   
> +static int child_reset_signals(void)
> +{
> +	int err = 0;
> +	struct sigaction sa = { .sa_handler = SIG_DFL, };
> +
> +	if (sigaction(SIGTERM, &sa, NULL) == -1)
> +		err = errno;
> +	if (sigaction(SIGINT, &sa, NULL) == -1 && !err)
> +		err = errno;
> +	if (sigaction(SIGCHLD, &sa, NULL) == -1 && !err)
> +		err = errno;
> +
> +	if (sigprocmask(SIG_SETMASK, &orig_sigmask, NULL) == -1 && !err)
> +		err = errno;
> +
> +	if (err)
> +		log(LOG_ERR, "error resetting signal handlers and mask\n");
> +	return -err;
> +}
> +
>   static int monitor_get_fc_uev_props(struct udev_device *ud,
>   				    char *traddr, size_t tra_sz,
>   				    char *host_traddr, size_t htra_sz)
> @@ -176,8 +198,12 @@ static int monitor_discovery(char *transport, char *traddr, char *trsvcid,
>   	if (pid == -1) {
>   		log(LOG_ERR, "failed to fork discovery task: %m");
>   		return -errno;
> -	} else if (pid > 0)
> +	} else if (pid > 0) {
> +		log(LOG_DEBUG, "started discovery task %ld\n", (long)pid);
>   		return 0;
> +	}
> +
> +	child_reset_signals();
>   
>   	log(LOG_NOTICE, "starting %s discovery for %s==>%s(%s)\n",
>   	    transport, host_traddr, traddr, trsvcid ? trsvcid : "none");
> 


From sagi at grimberg.me  Thu Jan 28 20:54:32 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Thu, 28 Jan 2021 17:54:32 -0800
Subject: [PATCH 17/35] monitor: handle SIGCHLD for terminated child
 processes
In-Reply-To: <20210126203324.23610-18-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-18-mwilck@suse.com>
Message-ID: <e1a56fb5-8aeb-d929-caff-3b7c5000b55c@grimberg.me>

No commit message?
> Signed-off-by: Martin Wilck <mwilck at suse.com>
> ---
>   monitor.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++--
>   1 file changed, 48 insertions(+), 2 deletions(-)
> 
> diff --git a/monitor.c b/monitor.c
> index 9375a14..8db40e6 100644
> --- a/monitor.c
> +++ b/monitor.c
> @@ -26,6 +26,8 @@
>   #include <limits.h>
>   #include <syslog.h>
>   #include <sys/stat.h>
> +#include <sys/types.h>
> +#include <sys/wait.h>
>   #include <sys/epoll.h>
>   
>   #include "common.h"
> @@ -100,6 +102,13 @@ static void monitor_int_handler(int sig)
>   	must_exit = 1;
>   }
>   
> +static sig_atomic_t got_sigchld;
> +
> +static void monitor_chld_handler(int sig)
> +{
> +	got_sigchld = 1;
> +}
> +
>   static sigset_t orig_sigmask;
>   
>   static int monitor_init_signals(void)
> @@ -118,6 +127,9 @@ static int monitor_init_signals(void)
>   		return -errno;
>   	if (sigaction(SIGINT, &sa, NULL) == -1)
>   		return -errno;
> +	sa.sa_handler = monitor_chld_handler;
> +	if (sigaction(SIGCHLD, &sa, NULL) == -1)
> +		return -errno;
>   	return 0;
>   }
>   
> @@ -336,6 +348,34 @@ static void monitor_handle_uevents(struct udev_monitor *monitor)
>   	}
>   }
>   
> +static void handle_sigchld(void)
> +{
> +	while (true) {
> +		int wstatus;
> +		pid_t pid;
> +
> +		pid = waitpid(-1, &wstatus, WNOHANG);
> +		switch(pid) {
> +		case -1:
> +			if (errno != ECHILD)
> +				log(LOG_ERR, "error in waitpid: %m\n");
> +			return;
> +		case 0:
> +			return;
> +		default:
> +			break;
> +		}
> +		if (!WIFEXITED(wstatus))
> +			log(LOG_WARNING, "child %ld didn't exit normally\n",
> +			    (long)pid);
> +		else if (WEXITSTATUS(wstatus) != 0)
> +			log(LOG_NOTICE, "child %ld exited with status \"%s\"\n",
> +			    (long)pid, strerror(WEXITSTATUS(wstatus)));
> +		else
> +			log(LOG_DEBUG, "child %ld exited normally\n", (long)pid);
> +	};
> +}
> +
>   #define MAX_EVENTS 1
>   static int monitor_main_loop(struct udev_monitor *monitor)
>   {
> @@ -357,13 +397,19 @@ static int monitor_main_loop(struct udev_monitor *monitor)
>   	sigfillset(&ep_mask);
>   	sigdelset(&ep_mask, SIGTERM);
>   	sigdelset(&ep_mask, SIGINT);
> +	sigdelset(&ep_mask, SIGCHLD);
>   	while (1) {
>   		int rc, i;
>   
>   		rc = epoll_pwait(ep_fd, events, MAX_EVENTS, -1, &ep_mask);
>   		if (rc == -1 && errno == EINTR) {
> -			log(LOG_NOTICE, "monitor: exit signal received\n");
> -			return 0;
> +			if (must_exit) {
> +				log(LOG_NOTICE, "monitor: exit signal received\n");
> +				return 0;
> +			} else if (got_sigchld) {
> +				got_sigchld = 0;
> +				handle_sigchld();
> +			}
>   		} else if (rc == -1) {
>   			log(LOG_ERR, "monitor: epoll_wait: %m\n");
>   			return -errno;
> 


From sagi at grimberg.me  Thu Jan 28 20:59:13 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Thu, 28 Jan 2021 17:59:13 -0800
Subject: [PATCH 22/35] conn-db: add simple connection registry
In-Reply-To: <20210126203324.23610-23-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-23-mwilck@suse.com>
Message-ID: <322b27a0-ff3e-265b-4c69-fae54466631e@grimberg.me>


> From: Martin Wilck <mwilck at suse.com>
> 
> The monitor works best if it maintains a discovery controller connection
> to every transport address that provides a discovery subsystem.
> 
> While controllers are easily tracked in sysfs, addresses ("connections"),
> i.e. (transport, traddr, trsvid, host_traddr) tuples, are not. Create
> a simple registry that tracks the state of "connections" and their
> associated discovery controllers.
> 
> A detailed description of the API is provided in the header file conn-db.h.

If this is more flexible, perhaps also the main fabrics 
discover/connect/connect-all can be converted to use it as well.


From lengchao at huawei.com  Thu Jan 28 21:48:57 2021
From: lengchao at huawei.com (Chao Leng)
Date: Fri, 29 Jan 2021 10:48:57 +0800
Subject: [PATCH v4 4/5] nvme-rdma: avoid IO error for nvme native multipath
In-Reply-To: <ca300cac-1f6c-01b2-8691-9a545381523a@grimberg.me>
References: <20210126081539.13320-1-lengchao@huawei.com>
 <20210126081539.13320-5-lengchao@huawei.com>
 <5a368693-65fd-1bdf-924a-f90df7f59b2a@grimberg.me>
 <9c30b18a-6fdd-be1c-f3bc-1d44c35ae274@huawei.com>
 <ca300cac-1f6c-01b2-8691-9a545381523a@grimberg.me>
Message-ID: <29ccc5e0-66e9-93db-e9b9-09012f1c8fe2@huawei.com>



On 2021/1/29 9:35, Sagi Grimberg wrote:
> 
>>>> @@ -2084,8 +2085,10 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
>>>> ????? err = nvme_rdma_post_send(queue, sqe, req->sge, req->num_sge,
>>>> ????????????? req->mr ? &req->reg_wr.wr : NULL);
>>>> -??? if (unlikely(err))
>>>> +??? if (unlikely(err)) {
>>>> +??????? driver_error = true;
>>>> ????????? goto err_unmap;
>>>
>>> Why not just call set the status and call nvme_rdma_complete_rq and
>>> return here?
>> If the err is ENOMEM or EAGAIN, I am not sure the err must be a
>> path-related error for all HBA drivers. So reused the error check code.
>> I think it would be more reasonable to assume any errors returned by HBA
>> driver as path-related errors.
>> If you think so, I will modify it in next patch version.
> 
> Meant to do that only for -EIO. We should absolutely not do any of this
> for stuff like EINVAL, EOPNOTSUPP, EPERM or any strange error that may
> return due to a bug or anything like that.
ok, please review again, thank you.
---
  drivers/nvme/host/rdma.c | 9 +++++++--
  1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index b7ce4f221d99..66b697461bd9 100644
--- a/drivers/nvme/host/rdma.c
+++ b/drivers/nvme/host/rdma.c
@@ -2084,8 +2084,13 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,

         err = nvme_rdma_post_send(queue, sqe, req->sge, req->num_sge,
                         req->mr ? &req->reg_wr.wr : NULL);
-       if (unlikely(err))
+       if (unlikely(err)) {
+               if (err == -EIO) {
+                       nvme_complete_failed_rq(rq, NVME_SC_HOST_PATH_ERROR);
+                       err = 0;
+               }
                 goto err_unmap;
+       }

         return BLK_STS_OK;

@@ -2094,7 +2099,7 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
  err:
         if (err == -ENOMEM || err == -EAGAIN)
                 ret = BLK_STS_RESOURCE;
-       else
+       else if (err)
                 ret = BLK_STS_IOERR;
         nvme_cleanup_cmd(rq);
  unmap_qe:
-- 
> .


From lengchao at huawei.com  Thu Jan 28 22:07:59 2021
From: lengchao at huawei.com (Chao Leng)
Date: Fri, 29 Jan 2021 11:07:59 +0800
Subject: [PATCH v2] nvme-multipath: Early exit if no path is available
In-Reply-To: <675d3cf7-1ae8-adc5-b6d0-359fe10f6b23@grimberg.me>
References: <20210127103033.15318-1-dwagner@suse.de>
 <db9baae0-547c-7ff4-8b2c-0b95f14be67c@huawei.com>
 <20210128075837.u5u56t23fq5gu6ou@beryllium.lan>
 <69575290-200e-b4a1-4269-c71e4c2cc37b@huawei.com>
 <20210128094004.erwnszjqcxlsi2kd@beryllium.lan>
 <ebb1d098-3ded-e592-4419-e905aabe824f@huawei.com>
 <675d3cf7-1ae8-adc5-b6d0-359fe10f6b23@grimberg.me>
Message-ID: <59cd053e-46cb-0235-141f-4ce919c93f48@huawei.com>



On 2021/1/29 9:42, Sagi Grimberg wrote:
> 
>>> You can't see exactly where it dies but I followed the assembly to
>>> nvme_round_robin_path(). Maybe it's not the initial nvme_next_ns(head,
>>> old) which returns NULL but nvme_next_ns() is returning NULL eventually
>>> (list_next_or_null_rcu()).
>> So there is other bug cause nvme_next_ns abormal.
>> I review the code about head->list and head->current_path, I find 2 bugs
>> may cause the bug:
>> First, I already send the patch. see:
>> https://lore.kernel.org/linux-nvme/20210128033351.22116-1-lengchao at huawei.com/
>> Second, in nvme_ns_remove, list_del_rcu is before
>> nvme_mpath_clear_current_path. This may cause "old" is deleted from the
>> "head", but still use "old". I'm not sure there's any other
>> consideration here, I will check it and try to fix it.
> 
> The reason why we first remove from head->list and only then clear
> current_path is because the other way around there is no way
> to guarantee that that the ns won't be assigned as current_path
> again (because it is in head->list).
ok, I see.
> 
> nvme_ns_remove fences continue of deletion of the ns by synchronizing
> the srcu such that for sure the current_path clearance is visible.
The list will be like this:
head->next = ns1;
ns1->next = head;
old->next = ns1;
This may cause infinite loop in nvme_round_robin_path.
for (ns = nvme_next_ns(head, old);
	ns != old;
	ns = nvme_next_ns(head, ns))
The ns will always be ns1, and then infinite loop.
> .


From sagi at grimberg.me  Thu Jan 28 22:24:15 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Thu, 28 Jan 2021 19:24:15 -0800
Subject: [PATCH v4 4/5] nvme-rdma: avoid IO error for nvme native multipath
In-Reply-To: <29ccc5e0-66e9-93db-e9b9-09012f1c8fe2@huawei.com>
References: <20210126081539.13320-1-lengchao@huawei.com>
 <20210126081539.13320-5-lengchao@huawei.com>
 <5a368693-65fd-1bdf-924a-f90df7f59b2a@grimberg.me>
 <9c30b18a-6fdd-be1c-f3bc-1d44c35ae274@huawei.com>
 <ca300cac-1f6c-01b2-8691-9a545381523a@grimberg.me>
 <29ccc5e0-66e9-93db-e9b9-09012f1c8fe2@huawei.com>
Message-ID: <1651456a-3251-77db-42c9-fc1a2d2c5c13@grimberg.me>


>>>> Why not just call set the status and call nvme_rdma_complete_rq and
>>>> return here?
>>> If the err is ENOMEM or EAGAIN, I am not sure the err must be a
>>> path-related error for all HBA drivers. So reused the error check code.
>>> I think it would be more reasonable to assume any errors returned by HBA
>>> driver as path-related errors.
>>> If you think so, I will modify it in next patch version.
>>
>> Meant to do that only for -EIO. We should absolutely not do any of this
>> for stuff like EINVAL, EOPNOTSUPP, EPERM or any strange error that may
>> return due to a bug or anything like that.
> ok, please review again, thank you.
> ---
>  ?drivers/nvme/host/rdma.c | 9 +++++++--
>  ?1 file changed, 7 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
> index b7ce4f221d99..66b697461bd9 100644
> --- a/drivers/nvme/host/rdma.c
> +++ b/drivers/nvme/host/rdma.c
> @@ -2084,8 +2084,13 @@ static blk_status_t nvme_rdma_queue_rq(struct 
> blk_mq_hw_ctx *hctx,
> 
>  ??????? err = nvme_rdma_post_send(queue, sqe, req->sge, req->num_sge,
>  ??????????????????????? req->mr ? &req->reg_wr.wr : NULL);
> -?????? if (unlikely(err))
> +?????? if (unlikely(err)) {
> +?????????????? if (err == -EIO) {
> +?????????????????????? nvme_complete_failed_rq(rq, 
> NVME_SC_HOST_PATH_ERROR);

I was thinking about:
--
         err = nvme_rdma_post_send(queue, sqe, req->sge, req->num_sge,
                         req->mr ? &req->reg_wr.wr : NULL);
         if (unlikely(err)) {
                 if (err == -EIO) {
                         /*
                          * Fail the reuqest so upper layer can failover I/O
                          * if another path is available
                          */
                         req->status = NVME_SC_HOST_PATH_ERROR;
                         nvme_rdma_complete_rq(rq);
                         return BLK_STS_OK;

                 }
                 goto err_unmap;
         }
--


From sagi at grimberg.me  Thu Jan 28 22:30:07 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Thu, 28 Jan 2021 19:30:07 -0800
Subject: [PATCH v2] nvme-multipath: Early exit if no path is available
In-Reply-To: <59cd053e-46cb-0235-141f-4ce919c93f48@huawei.com>
References: <20210127103033.15318-1-dwagner@suse.de>
 <db9baae0-547c-7ff4-8b2c-0b95f14be67c@huawei.com>
 <20210128075837.u5u56t23fq5gu6ou@beryllium.lan>
 <69575290-200e-b4a1-4269-c71e4c2cc37b@huawei.com>
 <20210128094004.erwnszjqcxlsi2kd@beryllium.lan>
 <ebb1d098-3ded-e592-4419-e905aabe824f@huawei.com>
 <675d3cf7-1ae8-adc5-b6d0-359fe10f6b23@grimberg.me>
 <59cd053e-46cb-0235-141f-4ce919c93f48@huawei.com>
Message-ID: <dbc39e56-b2bd-a82e-499a-5032c9716855@grimberg.me>


>>>> You can't see exactly where it dies but I followed the assembly to
>>>> nvme_round_robin_path(). Maybe it's not the initial nvme_next_ns(head,
>>>> old) which returns NULL but nvme_next_ns() is returning NULL eventually
>>>> (list_next_or_null_rcu()).
>>> So there is other bug cause nvme_next_ns abormal.
>>> I review the code about head->list and head->current_path, I find 2 bugs
>>> may cause the bug:
>>> First, I already send the patch. see:
>>> https://lore.kernel.org/linux-nvme/20210128033351.22116-1-lengchao at huawei.com/ 
>>>
>>> Second, in nvme_ns_remove, list_del_rcu is before
>>> nvme_mpath_clear_current_path. This may cause "old" is deleted from the
>>> "head", but still use "old". I'm not sure there's any other
>>> consideration here, I will check it and try to fix it.
>>
>> The reason why we first remove from head->list and only then clear
>> current_path is because the other way around there is no way
>> to guarantee that that the ns won't be assigned as current_path
>> again (because it is in head->list).
> ok, I see.
>>
>> nvme_ns_remove fences continue of deletion of the ns by synchronizing
>> the srcu such that for sure the current_path clearance is visible.
> The list will be like this:
> head->next = ns1;
> ns1->next = head;
> old->next = ns1;
> This may cause infinite loop in nvme_round_robin_path.
> for (ns = nvme_next_ns(head, old);
>  ????ns != old;
>  ????ns = nvme_next_ns(head, ns))
> The ns will always be ns1, and then infinite loop.

Who is being removed? I'm not following


From lengchao at huawei.com  Thu Jan 28 22:30:46 2021
From: lengchao at huawei.com (Chao Leng)
Date: Fri, 29 Jan 2021 11:30:46 +0800
Subject: [PATCH v4 4/5] nvme-rdma: avoid IO error for nvme native multipath
In-Reply-To: <1651456a-3251-77db-42c9-fc1a2d2c5c13@grimberg.me>
References: <20210126081539.13320-1-lengchao@huawei.com>
 <20210126081539.13320-5-lengchao@huawei.com>
 <5a368693-65fd-1bdf-924a-f90df7f59b2a@grimberg.me>
 <9c30b18a-6fdd-be1c-f3bc-1d44c35ae274@huawei.com>
 <ca300cac-1f6c-01b2-8691-9a545381523a@grimberg.me>
 <29ccc5e0-66e9-93db-e9b9-09012f1c8fe2@huawei.com>
 <1651456a-3251-77db-42c9-fc1a2d2c5c13@grimberg.me>
Message-ID: <b5b70392-d4f7-6f0c-d337-a6023dc4b992@huawei.com>



On 2021/1/29 11:24, Sagi Grimberg wrote:
> 
>>>>> Why not just call set the status and call nvme_rdma_complete_rq and
>>>>> return here?
>>>> If the err is ENOMEM or EAGAIN, I am not sure the err must be a
>>>> path-related error for all HBA drivers. So reused the error check code.
>>>> I think it would be more reasonable to assume any errors returned by HBA
>>>> driver as path-related errors.
>>>> If you think so, I will modify it in next patch version.
>>>
>>> Meant to do that only for -EIO. We should absolutely not do any of this
>>> for stuff like EINVAL, EOPNOTSUPP, EPERM or any strange error that may
>>> return due to a bug or anything like that.
>> ok, please review again, thank you.
>> ---
>> ??drivers/nvme/host/rdma.c | 9 +++++++--
>> ??1 file changed, 7 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
>> index b7ce4f221d99..66b697461bd9 100644
>> --- a/drivers/nvme/host/rdma.c
>> +++ b/drivers/nvme/host/rdma.c
>> @@ -2084,8 +2084,13 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
>>
>> ???????? err = nvme_rdma_post_send(queue, sqe, req->sge, req->num_sge,
>> ???????????????????????? req->mr ? &req->reg_wr.wr : NULL);
>> -?????? if (unlikely(err))
>> +?????? if (unlikely(err)) {
>> +?????????????? if (err == -EIO) {
>> +?????????????????????? nvme_complete_failed_rq(rq, NVME_SC_HOST_PATH_ERROR);
> 
> I was thinking about:
> -- 
>  ??????? err = nvme_rdma_post_send(queue, sqe, req->sge, req->num_sge,
>  ??????????????????????? req->mr ? &req->reg_wr.wr : NULL);
>  ??????? if (unlikely(err)) {
>  ??????????????? if (err == -EIO) {
>  ??????????????????????? /*
>  ???????????????????????? * Fail the reuqest so upper layer can failover I/O
>  ???????????????????????? * if another path is available
>  ???????????????????????? */
>  ??????????????????????? req->status = NVME_SC_HOST_PATH_ERROR;
>  ??????????????????????? nvme_rdma_complete_rq(rq);
>  ??????????????????????? return BLK_STS_OK;Need to do clean. so can not directly return.
> 
>  ??????????????? }
>  ??????????????? goto err_unmap;
>  ??????? }
> -- 
> .


From lengchao at huawei.com  Thu Jan 28 22:36:08 2021
From: lengchao at huawei.com (Chao Leng)
Date: Fri, 29 Jan 2021 11:36:08 +0800
Subject: [PATCH v2] nvme-multipath: Early exit if no path is available
In-Reply-To: <dbc39e56-b2bd-a82e-499a-5032c9716855@grimberg.me>
References: <20210127103033.15318-1-dwagner@suse.de>
 <db9baae0-547c-7ff4-8b2c-0b95f14be67c@huawei.com>
 <20210128075837.u5u56t23fq5gu6ou@beryllium.lan>
 <69575290-200e-b4a1-4269-c71e4c2cc37b@huawei.com>
 <20210128094004.erwnszjqcxlsi2kd@beryllium.lan>
 <ebb1d098-3ded-e592-4419-e905aabe824f@huawei.com>
 <675d3cf7-1ae8-adc5-b6d0-359fe10f6b23@grimberg.me>
 <59cd053e-46cb-0235-141f-4ce919c93f48@huawei.com>
 <dbc39e56-b2bd-a82e-499a-5032c9716855@grimberg.me>
Message-ID: <a3c64c60-13f3-1b99-47bc-05ebfefed343@huawei.com>



On 2021/1/29 11:30, Sagi Grimberg wrote:
> 
>>>>> You can't see exactly where it dies but I followed the assembly to
>>>>> nvme_round_robin_path(). Maybe it's not the initial nvme_next_ns(head,
>>>>> old) which returns NULL but nvme_next_ns() is returning NULL eventually
>>>>> (list_next_or_null_rcu()).
>>>> So there is other bug cause nvme_next_ns abormal.
>>>> I review the code about head->list and head->current_path, I find 2 bugs
>>>> may cause the bug:
>>>> First, I already send the patch. see:
>>>> https://lore.kernel.org/linux-nvme/20210128033351.22116-1-lengchao at huawei.com/
>>>> Second, in nvme_ns_remove, list_del_rcu is before
>>>> nvme_mpath_clear_current_path. This may cause "old" is deleted from the
>>>> "head", but still use "old". I'm not sure there's any other
>>>> consideration here, I will check it and try to fix it.
>>>
>>> The reason why we first remove from head->list and only then clear
>>> current_path is because the other way around there is no way
>>> to guarantee that that the ns won't be assigned as current_path
>>> again (because it is in head->list).
>> ok, I see.
>>>
>>> nvme_ns_remove fences continue of deletion of the ns by synchronizing
>>> the srcu such that for sure the current_path clearance is visible.
>> The list will be like this:
>> head->next = ns1;
>> ns1->next = head;
>> old->next = ns1;
>> This may cause infinite loop in nvme_round_robin_path.
>> for (ns = nvme_next_ns(head, old);
>> ?????ns != old;
>> ?????ns = nvme_next_ns(head, ns))
>> The ns will always be ns1, and then infinite loop.
> 
> Who is being removed? I'm not following
The "old" is being removed path.
Daniel Wagner report crash like this:
head->next = head;
old->next = head;
So nvme_next_ns(head, old) will return NULL, and then crash.
Although check ns can avoid crash, but can not avoid infinite loop.

Similar reason, The list will be like this:
head->next = ns1;
ns1->next = head;
old->next = ns1;
ns1 is other path.

> .


From lengchao at huawei.com  Thu Jan 28 22:37:21 2021
From: lengchao at huawei.com (Chao Leng)
Date: Fri, 29 Jan 2021 11:37:21 +0800
Subject: [PATCH v4 4/5] nvme-rdma: avoid IO error for nvme native multipath
In-Reply-To: <1651456a-3251-77db-42c9-fc1a2d2c5c13@grimberg.me>
References: <20210126081539.13320-1-lengchao@huawei.com>
 <20210126081539.13320-5-lengchao@huawei.com>
 <5a368693-65fd-1bdf-924a-f90df7f59b2a@grimberg.me>
 <9c30b18a-6fdd-be1c-f3bc-1d44c35ae274@huawei.com>
 <ca300cac-1f6c-01b2-8691-9a545381523a@grimberg.me>
 <29ccc5e0-66e9-93db-e9b9-09012f1c8fe2@huawei.com>
 <1651456a-3251-77db-42c9-fc1a2d2c5c13@grimberg.me>
Message-ID: <6b01cd8e-a153-1913-4e2f-0c3ce1029ccf@huawei.com>



On 2021/1/29 11:24, Sagi Grimberg wrote:
> 
>>>>> Why not just call set the status and call nvme_rdma_complete_rq and
>>>>> return here?
>>>> If the err is ENOMEM or EAGAIN, I am not sure the err must be a
>>>> path-related error for all HBA drivers. So reused the error check code.
>>>> I think it would be more reasonable to assume any errors returned by HBA
>>>> driver as path-related errors.
>>>> If you think so, I will modify it in next patch version.
>>>
>>> Meant to do that only for -EIO. We should absolutely not do any of this
>>> for stuff like EINVAL, EOPNOTSUPP, EPERM or any strange error that may
>>> return due to a bug or anything like that.
>> ok, please review again, thank you.
>> ---
>> ??drivers/nvme/host/rdma.c | 9 +++++++--
>> ??1 file changed, 7 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
>> index b7ce4f221d99..66b697461bd9 100644
>> --- a/drivers/nvme/host/rdma.c
>> +++ b/drivers/nvme/host/rdma.c
>> @@ -2084,8 +2084,13 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
>>
>> ???????? err = nvme_rdma_post_send(queue, sqe, req->sge, req->num_sge,
>> ???????????????????????? req->mr ? &req->reg_wr.wr : NULL);
>> -?????? if (unlikely(err))
>> +?????? if (unlikely(err)) {
>> +?????????????? if (err == -EIO) {
>> +?????????????????????? nvme_complete_failed_rq(rq, NVME_SC_HOST_PATH_ERROR);
> 
> I was thinking about:
> -- 
>  ??????? err = nvme_rdma_post_send(queue, sqe, req->sge, req->num_sge,
>  ??????????????????????? req->mr ? &req->reg_wr.wr : NULL);
>  ??????? if (unlikely(err)) {
>  ??????????????? if (err == -EIO) {
>  ??????????????????????? /*
>  ???????????????????????? * Fail the reuqest so upper layer can failover I/O
>  ???????????????????????? * if another path is available
>  ???????????????????????? */
>  ??????????????????????? req->status = NVME_SC_HOST_PATH_ERROR;
>  ??????????????????????? nvme_rdma_complete_rq(rq);
>  ??????????????????????? return BLK_STS_OK;
Need to do clean. so can not directly return.
> 
>  ??????????????? }
>  ??????????????? goto err_unmap;
>  ??????? }
> -- 
> .


From sagi at grimberg.me  Thu Jan 28 22:37:33 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Thu, 28 Jan 2021 19:37:33 -0800
Subject: [PATCH v4 4/5] nvme-rdma: avoid IO error for nvme native multipath
In-Reply-To: <b5b70392-d4f7-6f0c-d337-a6023dc4b992@huawei.com>
References: <20210126081539.13320-1-lengchao@huawei.com>
 <20210126081539.13320-5-lengchao@huawei.com>
 <5a368693-65fd-1bdf-924a-f90df7f59b2a@grimberg.me>
 <9c30b18a-6fdd-be1c-f3bc-1d44c35ae274@huawei.com>
 <ca300cac-1f6c-01b2-8691-9a545381523a@grimberg.me>
 <29ccc5e0-66e9-93db-e9b9-09012f1c8fe2@huawei.com>
 <1651456a-3251-77db-42c9-fc1a2d2c5c13@grimberg.me>
 <b5b70392-d4f7-6f0c-d337-a6023dc4b992@huawei.com>
Message-ID: <a55689cc-0925-c3a3-b7bf-e155cc3d4fe9@grimberg.me>


>>> diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
>>> index b7ce4f221d99..66b697461bd9 100644
>>> --- a/drivers/nvme/host/rdma.c
>>> +++ b/drivers/nvme/host/rdma.c
>>> @@ -2084,8 +2084,13 @@ static blk_status_t nvme_rdma_queue_rq(struct 
>>> blk_mq_hw_ctx *hctx,
>>>
>>> ???????? err = nvme_rdma_post_send(queue, sqe, req->sge, req->num_sge,
>>> ???????????????????????? req->mr ? &req->reg_wr.wr : NULL);
>>> -?????? if (unlikely(err))
>>> +?????? if (unlikely(err)) {
>>> +?????????????? if (err == -EIO) {
>>> +?????????????????????? nvme_complete_failed_rq(rq, 
>>> NVME_SC_HOST_PATH_ERROR);
>>
>> I was thinking about:
>> -- 
>> ???????? err = nvme_rdma_post_send(queue, sqe, req->sge, req->num_sge,
>> ???????????????????????? req->mr ? &req->reg_wr.wr : NULL);
>> ???????? if (unlikely(err)) {
>> ???????????????? if (err == -EIO) {
>> ???????????????????????? /*
>> ????????????????????????? * Fail the reuqest so upper layer can 
>> failover I/O
>> ????????????????????????? * if another path is available
>> ????????????????????????? */
>> ???????????????????????? req->status = NVME_SC_HOST_PATH_ERROR;
>> ???????????????????????? nvme_rdma_complete_rq(rq);
>> ???????????????????????? return BLK_STS_OK;Need to do clean. so can 
>> not directly return.

The completion path cleans up though

>>
>> ???????????????? }
>> ???????????????? goto err_unmap;
>> ???????? }
>> -- 
>> .
> 
> _______________________________________________
> Linux-nvme mailing list
> Linux-nvme at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-nvme


From Damien.LeMoal at wdc.com  Thu Jan 28 22:48:32 2021
From: Damien.LeMoal at wdc.com (Damien Le Moal)
Date: Fri, 29 Jan 2021 03:48:32 +0000
Subject: [PATCH] nvme: add tracing of zns commands
References: <46eeed2fcf2530d02fe5727a0a91a6e4675f6edd.1611683161.git.johannes.thumshirn@wdc.com>
Message-ID: <CH2PR04MB6522315BC122D9F1CFE645C1E7B99@CH2PR04MB6522.namprd04.prod.outlook.com>

On 2021/01/27 7:14, Johannes Thumshirn wrote:
> When support for the NVMe ZNS commands was merged, tracing of these has
> been omitted.
> 
> Add nvme_cmd_zone_mgmt_send, nvme_cmd_zone_mgmt_recv as well as
> nvme_cmd_zone_append to the nvme driver's tracing facility.
> 
> Signed-off-by: Johannes Thumshirn <johannes.thumshirn at wdc.com>
> ---
>  drivers/nvme/host/trace.c | 34 ++++++++++++++++++++++++++++++++++
>  include/linux/nvme.h      |  6 +++++-
>  2 files changed, 39 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/nvme/host/trace.c b/drivers/nvme/host/trace.c
> index 5c3cb6928f3c..9f9b6108de7d 100644
> --- a/drivers/nvme/host/trace.c
> +++ b/drivers/nvme/host/trace.c
> @@ -131,6 +131,35 @@ static const char *nvme_trace_dsm(struct trace_seq *p, u8 *cdw10)
>  	return ret;
>  }
>  
> +static const char *nvme_trace_zone_mgmt_send(struct trace_seq *p, u8 *cdw10)
> +{
> +	const char *ret = trace_seq_buffer_ptr(p);
> +	u64 slba = get_unaligned_le64(cdw10);
> +	u8 zsa = cdw10[12];
> +	u8 all = cdw10[13];
> +
> +	trace_seq_printf(p, "slba=%llu, zsa=%u, all=%u", slba, zsa, all);
> +	trace_seq_putc(p, 0);
> +
> +	return ret;
> +}
> +
> +static const char *nvme_trace_zone_mgmt_recv(struct trace_seq *p, u8 *cdw10)
> +{
> +	const char *ret = trace_seq_buffer_ptr(p);
> +	u64 slba = get_unaligned_le64(cdw10);
> +	u32 numd = get_unaligned_le32(cdw10 + 8);
> +	u8 zra = cdw10[12];
> +	u8 zrasf = cdw10[13];
> +	u8 pr = cdw10[14];
> +
> +	trace_seq_printf(p, "slba=%llu, numd=%u, zra=%u, zrasf=%u, pr=%u",
> +			 slba, numd, zra, zrasf, pr);
> +	trace_seq_putc(p, 0);
> +
> +	return ret;
> +}
> +
>  static const char *nvme_trace_common(struct trace_seq *p, u8 *cdw10)
>  {
>  	const char *ret = trace_seq_buffer_ptr(p);
> @@ -171,9 +200,14 @@ const char *nvme_trace_parse_nvm_cmd(struct trace_seq *p,
>  	case nvme_cmd_read:
>  	case nvme_cmd_write:
>  	case nvme_cmd_write_zeroes:
> +	case nvme_cmd_zone_append:
>  		return nvme_trace_read_write(p, cdw10);
>  	case nvme_cmd_dsm:
>  		return nvme_trace_dsm(p, cdw10);
> +	case nvme_cmd_zone_mgmt_send:
> +		return nvme_trace_zone_mgmt_send(p, cdw10);
> +	case nvme_cmd_zone_mgmt_recv:
> +		return nvme_trace_zone_mgmt_recv(p, cdw10);
>  	default:
>  		return nvme_trace_common(p, cdw10);
>  	}
> diff --git a/include/linux/nvme.h b/include/linux/nvme.h
> index bfed36e342cc..325dcdd221de 100644
> --- a/include/linux/nvme.h
> +++ b/include/linux/nvme.h
> @@ -697,7 +697,11 @@ enum nvme_opcode {
>  		nvme_opcode_name(nvme_cmd_resv_register),	\
>  		nvme_opcode_name(nvme_cmd_resv_report),		\
>  		nvme_opcode_name(nvme_cmd_resv_acquire),	\
> -		nvme_opcode_name(nvme_cmd_resv_release))
> +		nvme_opcode_name(nvme_cmd_resv_release),	\
> +		nvme_opcode_name(nvme_cmd_zone_mgmt_send),	\
> +		nvme_opcode_name(nvme_cmd_zone_mgmt_recv),	\
> +		nvme_opcode_name(nvme_cmd_zone_append))
> +
>  
>  
>  /*
> 

Looks OK to me.

Reviewed-by: Damien Le Moal <damien.lemoal at wdc.com>

-- 
Damien Le Moal
Western Digital Research


From lengchao at huawei.com  Thu Jan 28 22:50:28 2021
From: lengchao at huawei.com (Chao Leng)
Date: Fri, 29 Jan 2021 11:50:28 +0800
Subject: [PATCH v4 4/5] nvme-rdma: avoid IO error for nvme native multipath
In-Reply-To: <a55689cc-0925-c3a3-b7bf-e155cc3d4fe9@grimberg.me>
References: <20210126081539.13320-1-lengchao@huawei.com>
 <20210126081539.13320-5-lengchao@huawei.com>
 <5a368693-65fd-1bdf-924a-f90df7f59b2a@grimberg.me>
 <9c30b18a-6fdd-be1c-f3bc-1d44c35ae274@huawei.com>
 <ca300cac-1f6c-01b2-8691-9a545381523a@grimberg.me>
 <29ccc5e0-66e9-93db-e9b9-09012f1c8fe2@huawei.com>
 <1651456a-3251-77db-42c9-fc1a2d2c5c13@grimberg.me>
 <b5b70392-d4f7-6f0c-d337-a6023dc4b992@huawei.com>
 <a55689cc-0925-c3a3-b7bf-e155cc3d4fe9@grimberg.me>
Message-ID: <871fd11a-b4e7-aa63-97f0-be483b3e1f9e@huawei.com>



On 2021/1/29 11:37, Sagi Grimberg wrote:
> 
>>>> diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
>>>> index b7ce4f221d99..66b697461bd9 100644
>>>> --- a/drivers/nvme/host/rdma.c
>>>> +++ b/drivers/nvme/host/rdma.c
>>>> @@ -2084,8 +2084,13 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
>>>>
>>>> ???????? err = nvme_rdma_post_send(queue, sqe, req->sge, req->num_sge,
>>>> ???????????????????????? req->mr ? &req->reg_wr.wr : NULL);
>>>> -?????? if (unlikely(err))
>>>> +?????? if (unlikely(err)) {
>>>> +?????????????? if (err == -EIO) {
>>>> +?????????????????????? nvme_complete_failed_rq(rq, NVME_SC_HOST_PATH_ERROR);
>>>
>>> I was thinking about:
>>> -- 
>>> ???????? err = nvme_rdma_post_send(queue, sqe, req->sge, req->num_sge,
>>> ???????????????????????? req->mr ? &req->reg_wr.wr : NULL);
>>> ???????? if (unlikely(err)) {
>>> ???????????????? if (err == -EIO) {
>>> ???????????????????????? /*
>>> ????????????????????????? * Fail the reuqest so upper layer can failover I/O
>>> ????????????????????????? * if another path is available
>>> ????????????????????????? */
>>> ???????????????????????? req->status = NVME_SC_HOST_PATH_ERROR;
>>> ???????????????????????? nvme_rdma_complete_rq(rq);
>>> ???????????????????????? return BLK_STS_OK;Need to do clean. so can not directly return.
> 
> The completion path cleans up though
ok, i see.
But we need to use the new helper nvme_complete_failed_rq to avoid double request completion.
Or we can do like this:
req->status = NVME_SC_HOST_PATH_ERROR;
blk_mq_set_request_complete(req);
nvme_rdma_complete_rq(rq);
> 
>>>
>>> ???????????????? }
>>> ???????????????? goto err_unmap;
>>> ???????? }
>>> -- 
>>> .
>>
>> _______________________________________________
>> Linux-nvme mailing list
>> Linux-nvme at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-nvme
> .


From linux at leemhuis.info  Fri Jan 29 00:24:42 2021
From: linux at leemhuis.info (Thorsten Leemhuis)
Date: Fri, 29 Jan 2021 06:24:42 +0100
Subject: [PATCH] nvme-pci: add quirk to make Kingston A2000 SSD avoid deepest
 sleep state
Message-ID: <20210129052442.310780-1-linux@leemhuis.info>

Some Kingston A2000 NVMe SSDs sooner or later get confused and stop
working when they use the deepest APST sleep while running Linux. The
system then crashes and one has to cold boot it to get the SSD working
again.

Kingston seems to known about this since at least mid-September 2020:
https://bbs.archlinux.org/viewtopic.php?pid=1926994#p1926994

Someone working for a German company representing Kingston to the German
press confirmed to me Kingston engineering is aware of the issue and
investigating; the person stated that to their current knowledge only
the deepest APST sleep state causes trouble. Therefore, make Linux avoid
it for now by applying the NVME_QUIRK_NO_DEEPEST_PS to this SSD.

I have two such SSDs, but it seems the problem doesn't occur with them.
I hence couldn't verify if this patch really fixes the problem, but all
the data in front of me suggests it should.

This patch can easily be reverted or improved upon if a better solution
surfaces.

FWIW, there are many reports about the issue scattered around the web;
most of the users disabled APST completely to make things work, some
just made Linux avoid the deepest sleep state:

https://bugzilla.kernel.org/show_bug.cgi?id=195039#c65
https://bugzilla.kernel.org/show_bug.cgi?id=195039#c73
https://bugzilla.kernel.org/show_bug.cgi?id=195039#c74
https://bugzilla.kernel.org/show_bug.cgi?id=195039#c78
https://bugzilla.kernel.org/show_bug.cgi?id=195039#c79
https://bugzilla.kernel.org/show_bug.cgi?id=195039#c80
https://askubuntu.com/questions/1222049/nvmekingston-a2000-sometimes-stops-giving-response-in-ubuntu-18-04dell-inspir
https://community.acer.com/en/discussion/604326/m-2-nvme-ssd-aspire-517-51g-issue-compatibility-kingston-a2000-linux-ubuntu

For the record, some data from 'nvme id-ctrl /dev/nvme0'

NVME Identify Controller:
vid       : 0x2646
ssvid     : 0x2646
mn        : KINGSTON SA2000M81000G
fr        : S5Z42105
[...]
ps    0 : mp:9.00W operational enlat:0 exlat:0 rrt:0 rrl:0
          rwt:0 rwl:0 idle_power:- active_power:-
ps    1 : mp:4.60W operational enlat:0 exlat:0 rrt:1 rrl:1
          rwt:1 rwl:1 idle_power:- active_power:-
ps    2 : mp:3.80W operational enlat:0 exlat:0 rrt:2 rrl:2
          rwt:2 rwl:2 idle_power:- active_power:-
ps    3 : mp:0.0450W non-operational enlat:2000 exlat:2000 rrt:3 rrl:3
          rwt:3 rwl:3 idle_power:- active_power:-
ps    4 : mp:0.0040W non-operational enlat:15000 exlat:15000 rrt:4 rrl:4
          rwt:4 rwl:4 idle_power:- active_power:-

Cc: stable at vger.kernel.org # 4.14+
Signed-off-by: Thorsten Leemhuis <linux at leemhuis.info>
---

Once this is out I will post a link to it in
https://bugzilla.kernel.org/show_bug.cgi?id=195039, maybe someone there
might be able to confirm that this fixes the issue.

---
 drivers/nvme/host/pci.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 856aa31931c1..421735e16870 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -3257,6 +3257,8 @@ static const struct pci_device_id nvme_id_table[] = {
 		.driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
 	{ PCI_DEVICE(0x15b7, 0x2001),   /*  Sandisk Skyhawk */
 		.driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
+	{ PCI_DEVICE(0x2646, 0x2263),   /* KINGSTON A2000 NVMe SSD  */
+		.driver_data = NVME_QUIRK_NO_DEEPEST_PS, },
 	{ PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2001),
 		.driver_data = NVME_QUIRK_SINGLE_VECTOR },
 	{ PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2003) },
-- 
2.29.2



From lkp at intel.com  Fri Jan 29 01:55:26 2021
From: lkp at intel.com (kernel test robot)
Date: Fri, 29 Jan 2021 14:55:26 +0800
Subject: [linux-nvme:nvme-5.11] BUILD SUCCESS
 772ea326a4a00b6b4b2c8f3606ad10c31f46c511
Message-ID: <6013b15e.kDD7qEw96xUK70Cx%lkp@intel.com>

tree/branch: git://git.infradead.org/nvme.git nvme-5.11
branch HEAD: 772ea326a4a00b6b4b2c8f3606ad10c31f46c511  nvme-core: use list_add_tail_rcu instead of list_add_tail for nvme_init_ns_head

elapsed time: 722m

configs tested: 25
configs skipped: 3

The following configs have been built successfully.
More configs may be tested in the coming days.

gcc tested configs:
arm                                 defconfig
arm64                            allyesconfig
arm64                               defconfig
arm                              allyesconfig
arm                              allmodconfig
riscv                    nommu_k210_defconfig
riscv                            allyesconfig
riscv                    nommu_virt_defconfig
riscv                             allnoconfig
riscv                               defconfig
riscv                          rv32_defconfig
riscv                            allmodconfig
x86_64                                   rhel
x86_64                           allyesconfig
x86_64                    rhel-7.6-kselftests
x86_64                              defconfig
x86_64                               rhel-8.3
x86_64                      rhel-8.3-kbuiltin
x86_64                                  kexec

clang tested configs:
x86_64               randconfig-a002-20210128
x86_64               randconfig-a003-20210128
x86_64               randconfig-a001-20210128
x86_64               randconfig-a005-20210128
x86_64               randconfig-a006-20210128
x86_64               randconfig-a004-20210128

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all at lists.01.org


From hare at suse.de  Fri Jan 29 02:06:57 2021
From: hare at suse.de (Hannes Reinecke)
Date: Fri, 29 Jan 2021 08:06:57 +0100
Subject: [PATCH v2] nvme-multipath: Early exit if no path is available
In-Reply-To: <59cd053e-46cb-0235-141f-4ce919c93f48@huawei.com>
References: <20210127103033.15318-1-dwagner@suse.de>
 <db9baae0-547c-7ff4-8b2c-0b95f14be67c@huawei.com>
 <20210128075837.u5u56t23fq5gu6ou@beryllium.lan>
 <69575290-200e-b4a1-4269-c71e4c2cc37b@huawei.com>
 <20210128094004.erwnszjqcxlsi2kd@beryllium.lan>
 <ebb1d098-3ded-e592-4419-e905aabe824f@huawei.com>
 <675d3cf7-1ae8-adc5-b6d0-359fe10f6b23@grimberg.me>
 <59cd053e-46cb-0235-141f-4ce919c93f48@huawei.com>
Message-ID: <65392653-6b03-9195-f686-5fe4b3290bd2@suse.de>

On 1/29/21 4:07 AM, Chao Leng wrote:
> 
> 
> On 2021/1/29 9:42, Sagi Grimberg wrote:
>>
>>>> You can't see exactly where it dies but I followed the assembly to
>>>> nvme_round_robin_path(). Maybe it's not the initial nvme_next_ns(head,
>>>> old) which returns NULL but nvme_next_ns() is returning NULL eventually
>>>> (list_next_or_null_rcu()).
>>> So there is other bug cause nvme_next_ns abormal.
>>> I review the code about head->list and head->current_path, I find 2 bugs
>>> may cause the bug:
>>> First, I already send the patch. see:
>>> https://lore.kernel.org/linux-nvme/20210128033351.22116-1-lengchao at huawei.com/ 
>>>
>>> Second, in nvme_ns_remove, list_del_rcu is before
>>> nvme_mpath_clear_current_path. This may cause "old" is deleted from the
>>> "head", but still use "old". I'm not sure there's any other
>>> consideration here, I will check it and try to fix it.
>>
>> The reason why we first remove from head->list and only then clear
>> current_path is because the other way around there is no way
>> to guarantee that that the ns won't be assigned as current_path
>> again (because it is in head->list).
> ok, I see.
>>
>> nvme_ns_remove fences continue of deletion of the ns by synchronizing
>> the srcu such that for sure the current_path clearance is visible.
> The list will be like this:
> head->next = ns1;
> ns1->next = head;
> old->next = ns1;

Where does 'old' pointing to?

> This may cause infinite loop in nvme_round_robin_path.
> for (ns = nvme_next_ns(head, old);
>  ????ns != old;
>  ????ns = nvme_next_ns(head, ns))
> The ns will always be ns1, and then infinite loop.

No. nvme_next_ns() will return NULL.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare at suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 N?rnberg
HRB 36809 (AG N?rnberg), Gesch?ftsf?hrer: Felix Imend?rffer


From lengchao at huawei.com  Fri Jan 29 02:45:39 2021
From: lengchao at huawei.com (Chao Leng)
Date: Fri, 29 Jan 2021 15:45:39 +0800
Subject: [PATCH v2] nvme-multipath: Early exit if no path is available
In-Reply-To: <65392653-6b03-9195-f686-5fe4b3290bd2@suse.de>
References: <20210127103033.15318-1-dwagner@suse.de>
 <db9baae0-547c-7ff4-8b2c-0b95f14be67c@huawei.com>
 <20210128075837.u5u56t23fq5gu6ou@beryllium.lan>
 <69575290-200e-b4a1-4269-c71e4c2cc37b@huawei.com>
 <20210128094004.erwnszjqcxlsi2kd@beryllium.lan>
 <ebb1d098-3ded-e592-4419-e905aabe824f@huawei.com>
 <675d3cf7-1ae8-adc5-b6d0-359fe10f6b23@grimberg.me>
 <59cd053e-46cb-0235-141f-4ce919c93f48@huawei.com>
 <65392653-6b03-9195-f686-5fe4b3290bd2@suse.de>
Message-ID: <81b22bbf-4dd3-6161-e63a-9699690a4e4f@huawei.com>



On 2021/1/29 15:06, Hannes Reinecke wrote:
> On 1/29/21 4:07 AM, Chao Leng wrote:
>>
>>
>> On 2021/1/29 9:42, Sagi Grimberg wrote:
>>>
>>>>> You can't see exactly where it dies but I followed the assembly to
>>>>> nvme_round_robin_path(). Maybe it's not the initial nvme_next_ns(head,
>>>>> old) which returns NULL but nvme_next_ns() is returning NULL eventually
>>>>> (list_next_or_null_rcu()).
>>>> So there is other bug cause nvme_next_ns abormal.
>>>> I review the code about head->list and head->current_path, I find 2 bugs
>>>> may cause the bug:
>>>> First, I already send the patch. see:
>>>> https://lore.kernel.org/linux-nvme/20210128033351.22116-1-lengchao at huawei.com/
>>>> Second, in nvme_ns_remove, list_del_rcu is before
>>>> nvme_mpath_clear_current_path. This may cause "old" is deleted from the
>>>> "head", but still use "old". I'm not sure there's any other
>>>> consideration here, I will check it and try to fix it.
>>>
>>> The reason why we first remove from head->list and only then clear
>>> current_path is because the other way around there is no way
>>> to guarantee that that the ns won't be assigned as current_path
>>> again (because it is in head->list).
>> ok, I see.
>>>
>>> nvme_ns_remove fences continue of deletion of the ns by synchronizing
>>> the srcu such that for sure the current_path clearance is visible.
>> The list will be like this:
>> head->next = ns1;
>> ns1->next = head;
>> old->next = ns1;
> 
> Where does 'old' pointing to?
> 
>> This may cause infinite loop in nvme_round_robin_path.
>> for (ns = nvme_next_ns(head, old);
>> ?????ns != old;
>> ?????ns = nvme_next_ns(head, ns))
>> The ns will always be ns1, and then infinite loop.
> 
> No. nvme_next_ns() will return NULL.
If there is just one path(the "old") and the "old" is deleted,
nvme_next_ns() will return NULL.
The list like this:
head->next = head;
old->next = head;
If there is two or more path and the "old" is deleted,
"for" will be infinite loop. because nvme_next_ns() will return
the path which in the list except the "old", check condition will
be true for ever.
For example, there is two path: one is the "old", another is "ns1".
The list like this:
head->next = ns1;
ns1->next = head;
old->next = ns1;
nvme_next_ns(head, old) will return ns1;
Then nvme_next_ns(head, ns1) will return ns1;
And then infinite loop.
> 
> Cheers,
> 
> Hannes


From hare at suse.de  Fri Jan 29 03:33:19 2021
From: hare at suse.de (Hannes Reinecke)
Date: Fri, 29 Jan 2021 09:33:19 +0100
Subject: [PATCH v2] nvme-multipath: Early exit if no path is available
In-Reply-To: <81b22bbf-4dd3-6161-e63a-9699690a4e4f@huawei.com>
References: <20210127103033.15318-1-dwagner@suse.de>
 <db9baae0-547c-7ff4-8b2c-0b95f14be67c@huawei.com>
 <20210128075837.u5u56t23fq5gu6ou@beryllium.lan>
 <69575290-200e-b4a1-4269-c71e4c2cc37b@huawei.com>
 <20210128094004.erwnszjqcxlsi2kd@beryllium.lan>
 <ebb1d098-3ded-e592-4419-e905aabe824f@huawei.com>
 <675d3cf7-1ae8-adc5-b6d0-359fe10f6b23@grimberg.me>
 <59cd053e-46cb-0235-141f-4ce919c93f48@huawei.com>
 <65392653-6b03-9195-f686-5fe4b3290bd2@suse.de>
 <81b22bbf-4dd3-6161-e63a-9699690a4e4f@huawei.com>
Message-ID: <715dd943-0587-be08-2840-e0948cf0bc62@suse.de>

On 1/29/21 8:45 AM, Chao Leng wrote:
> 
> 
> On 2021/1/29 15:06, Hannes Reinecke wrote:
>> On 1/29/21 4:07 AM, Chao Leng wrote:
>>>
>>>
>>> On 2021/1/29 9:42, Sagi Grimberg wrote:
>>>>
>>>>>> You can't see exactly where it dies but I followed the assembly to
>>>>>> nvme_round_robin_path(). Maybe it's not the initial 
>>>>>> nvme_next_ns(head,
>>>>>> old) which returns NULL but nvme_next_ns() is returning NULL 
>>>>>> eventually
>>>>>> (list_next_or_null_rcu()).
>>>>> So there is other bug cause nvme_next_ns abormal.
>>>>> I review the code about head->list and head->current_path, I find 2 
>>>>> bugs
>>>>> may cause the bug:
>>>>> First, I already send the patch. see:
>>>>> https://lore.kernel.org/linux-nvme/20210128033351.22116-1-lengchao at huawei.com/ 
>>>>>
>>>>> Second, in nvme_ns_remove, list_del_rcu is before
>>>>> nvme_mpath_clear_current_path. This may cause "old" is deleted from 
>>>>> the
>>>>> "head", but still use "old". I'm not sure there's any other
>>>>> consideration here, I will check it and try to fix it.
>>>>
>>>> The reason why we first remove from head->list and only then clear
>>>> current_path is because the other way around there is no way
>>>> to guarantee that that the ns won't be assigned as current_path
>>>> again (because it is in head->list).
>>> ok, I see.
>>>>
>>>> nvme_ns_remove fences continue of deletion of the ns by synchronizing
>>>> the srcu such that for sure the current_path clearance is visible.
>>> The list will be like this:
>>> head->next = ns1;
>>> ns1->next = head;
>>> old->next = ns1;
>>
>> Where does 'old' pointing to?
>>
>>> This may cause infinite loop in nvme_round_robin_path.
>>> for (ns = nvme_next_ns(head, old);
>>> ?????ns != old;
>>> ?????ns = nvme_next_ns(head, ns))
>>> The ns will always be ns1, and then infinite loop.
>>
>> No. nvme_next_ns() will return NULL.
> If there is just one path(the "old") and the "old" is deleted,
> nvme_next_ns() will return NULL.
> The list like this:
> head->next = head;
> old->next = head;
> If there is two or more path and the "old" is deleted,
> "for" will be infinite loop. because nvme_next_ns() will return
> the path which in the list except the "old", check condition will
> be true for ever.

But that will be caught by the statement above:

if (list_is_singular(&head->list))

no?

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare at suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 N?rnberg
HRB 36809 (AG N?rnberg), Gesch?ftsf?hrer: Felix Imend?rffer


From lengchao at huawei.com  Fri Jan 29 03:46:16 2021
From: lengchao at huawei.com (Chao Leng)
Date: Fri, 29 Jan 2021 16:46:16 +0800
Subject: [PATCH v2] nvme-multipath: Early exit if no path is available
In-Reply-To: <715dd943-0587-be08-2840-e0948cf0bc62@suse.de>
References: <20210127103033.15318-1-dwagner@suse.de>
 <db9baae0-547c-7ff4-8b2c-0b95f14be67c@huawei.com>
 <20210128075837.u5u56t23fq5gu6ou@beryllium.lan>
 <69575290-200e-b4a1-4269-c71e4c2cc37b@huawei.com>
 <20210128094004.erwnszjqcxlsi2kd@beryllium.lan>
 <ebb1d098-3ded-e592-4419-e905aabe824f@huawei.com>
 <675d3cf7-1ae8-adc5-b6d0-359fe10f6b23@grimberg.me>
 <59cd053e-46cb-0235-141f-4ce919c93f48@huawei.com>
 <65392653-6b03-9195-f686-5fe4b3290bd2@suse.de>
 <81b22bbf-4dd3-6161-e63a-9699690a4e4f@huawei.com>
 <715dd943-0587-be08-2840-e0948cf0bc62@suse.de>
Message-ID: <eb131d8f-f009-42e7-105d-58b84060f0dd@huawei.com>



On 2021/1/29 16:33, Hannes Reinecke wrote:
> On 1/29/21 8:45 AM, Chao Leng wrote:
>>
>>
>> On 2021/1/29 15:06, Hannes Reinecke wrote:
>>> On 1/29/21 4:07 AM, Chao Leng wrote:
>>>>
>>>>
>>>> On 2021/1/29 9:42, Sagi Grimberg wrote:
>>>>>
>>>>>>> You can't see exactly where it dies but I followed the assembly to
>>>>>>> nvme_round_robin_path(). Maybe it's not the initial nvme_next_ns(head,
>>>>>>> old) which returns NULL but nvme_next_ns() is returning NULL eventually
>>>>>>> (list_next_or_null_rcu()).
>>>>>> So there is other bug cause nvme_next_ns abormal.
>>>>>> I review the code about head->list and head->current_path, I find 2 bugs
>>>>>> may cause the bug:
>>>>>> First, I already send the patch. see:
>>>>>> https://lore.kernel.org/linux-nvme/20210128033351.22116-1-lengchao at huawei.com/
>>>>>> Second, in nvme_ns_remove, list_del_rcu is before
>>>>>> nvme_mpath_clear_current_path. This may cause "old" is deleted from the
>>>>>> "head", but still use "old". I'm not sure there's any other
>>>>>> consideration here, I will check it and try to fix it.
>>>>>
>>>>> The reason why we first remove from head->list and only then clear
>>>>> current_path is because the other way around there is no way
>>>>> to guarantee that that the ns won't be assigned as current_path
>>>>> again (because it is in head->list).
>>>> ok, I see.
>>>>>
>>>>> nvme_ns_remove fences continue of deletion of the ns by synchronizing
>>>>> the srcu such that for sure the current_path clearance is visible.
>>>> The list will be like this:
>>>> head->next = ns1;
>>>> ns1->next = head;
>>>> old->next = ns1;
>>>
>>> Where does 'old' pointing to?
>>>
>>>> This may cause infinite loop in nvme_round_robin_path.
>>>> for (ns = nvme_next_ns(head, old);
>>>> ?????ns != old;
>>>> ?????ns = nvme_next_ns(head, ns))
>>>> The ns will always be ns1, and then infinite loop.
>>>
>>> No. nvme_next_ns() will return NULL.
>> If there is just one path(the "old") and the "old" is deleted,
>> nvme_next_ns() will return NULL.
>> The list like this:
>> head->next = head;
>> old->next = head;
>> If there is two or more path and the "old" is deleted,
>> "for" will be infinite loop. because nvme_next_ns() will return
>> the path which in the list except the "old", check condition will
>> be true for ever.
> 
> But that will be caught by the statement above:
> 
> if (list_is_singular(&head->list))
> 
> no?
Two path just a sample example.
If there is just two path, will enter it, may cause no path but there is
actually one path. It is falsely assumed that the "old" must be not deleted.
If there is more than two path, will cause infinite loop.
> 
> Cheers,
> 
> Hannes


From hare at suse.de  Fri Jan 29 04:20:44 2021
From: hare at suse.de (Hannes Reinecke)
Date: Fri, 29 Jan 2021 10:20:44 +0100
Subject: [PATCH v2] nvme-multipath: Early exit if no path is available
In-Reply-To: <eb131d8f-f009-42e7-105d-58b84060f0dd@huawei.com>
References: <20210127103033.15318-1-dwagner@suse.de>
 <db9baae0-547c-7ff4-8b2c-0b95f14be67c@huawei.com>
 <20210128075837.u5u56t23fq5gu6ou@beryllium.lan>
 <69575290-200e-b4a1-4269-c71e4c2cc37b@huawei.com>
 <20210128094004.erwnszjqcxlsi2kd@beryllium.lan>
 <ebb1d098-3ded-e592-4419-e905aabe824f@huawei.com>
 <675d3cf7-1ae8-adc5-b6d0-359fe10f6b23@grimberg.me>
 <59cd053e-46cb-0235-141f-4ce919c93f48@huawei.com>
 <65392653-6b03-9195-f686-5fe4b3290bd2@suse.de>
 <81b22bbf-4dd3-6161-e63a-9699690a4e4f@huawei.com>
 <715dd943-0587-be08-2840-e0948cf0bc62@suse.de>
 <eb131d8f-f009-42e7-105d-58b84060f0dd@huawei.com>
Message-ID: <ac019690-7f02-d28c-ed58-bfc8c1d48879@suse.de>

On 1/29/21 9:46 AM, Chao Leng wrote:
> 
> 
> On 2021/1/29 16:33, Hannes Reinecke wrote:
>> On 1/29/21 8:45 AM, Chao Leng wrote:
>>>
>>>
>>> On 2021/1/29 15:06, Hannes Reinecke wrote:
>>>> On 1/29/21 4:07 AM, Chao Leng wrote:
>>>>>
>>>>>
>>>>> On 2021/1/29 9:42, Sagi Grimberg wrote:
>>>>>>
>>>>>>>> You can't see exactly where it dies but I followed the assembly to
>>>>>>>> nvme_round_robin_path(). Maybe it's not the initial 
>>>>>>>> nvme_next_ns(head,
>>>>>>>> old) which returns NULL but nvme_next_ns() is returning NULL 
>>>>>>>> eventually
>>>>>>>> (list_next_or_null_rcu()).
>>>>>>> So there is other bug cause nvme_next_ns abormal.
>>>>>>> I review the code about head->list and head->current_path, I find 
>>>>>>> 2 bugs
>>>>>>> may cause the bug:
>>>>>>> First, I already send the patch. see:
>>>>>>> https://lore.kernel.org/linux-nvme/20210128033351.22116-1-lengchao at huawei.com/ 
>>>>>>>
>>>>>>> Second, in nvme_ns_remove, list_del_rcu is before
>>>>>>> nvme_mpath_clear_current_path. This may cause "old" is deleted 
>>>>>>> from the
>>>>>>> "head", but still use "old". I'm not sure there's any other
>>>>>>> consideration here, I will check it and try to fix it.
>>>>>>
>>>>>> The reason why we first remove from head->list and only then clear
>>>>>> current_path is because the other way around there is no way
>>>>>> to guarantee that that the ns won't be assigned as current_path
>>>>>> again (because it is in head->list).
>>>>> ok, I see.
>>>>>>
>>>>>> nvme_ns_remove fences continue of deletion of the ns by synchronizing
>>>>>> the srcu such that for sure the current_path clearance is visible.
>>>>> The list will be like this:
>>>>> head->next = ns1;
>>>>> ns1->next = head;
>>>>> old->next = ns1;
>>>>
>>>> Where does 'old' pointing to?
>>>>
>>>>> This may cause infinite loop in nvme_round_robin_path.
>>>>> for (ns = nvme_next_ns(head, old);
>>>>> ?????ns != old;
>>>>> ?????ns = nvme_next_ns(head, ns))
>>>>> The ns will always be ns1, and then infinite loop.
>>>>
>>>> No. nvme_next_ns() will return NULL.
>>> If there is just one path(the "old") and the "old" is deleted,
>>> nvme_next_ns() will return NULL.
>>> The list like this:
>>> head->next = head;
>>> old->next = head;
>>> If there is two or more path and the "old" is deleted,
>>> "for" will be infinite loop. because nvme_next_ns() will return
>>> the path which in the list except the "old", check condition will
>>> be true for ever.
>>
>> But that will be caught by the statement above:
>>
>> if (list_is_singular(&head->list))
>>
>> no?
> Two path just a sample example.
> If there is just two path, will enter it, may cause no path but there is
> actually one path. It is falsely assumed that the "old" must be not 
> deleted.
> If there is more than two path, will cause infinite loop.
So you mean we'll need something like this?

diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
index 71696819c228..8ffccaf9c19a 100644
--- a/drivers/nvme/host/multipath.c
+++ b/drivers/nvme/host/multipath.c
@@ -202,10 +202,12 @@ static struct nvme_ns *__nvme_find_path(struct 
nvme_ns_head *head, int node)
  static struct nvme_ns *nvme_next_ns(struct nvme_ns_head *head,
                 struct nvme_ns *ns)
  {
-       ns = list_next_or_null_rcu(&head->list, &ns->siblings, struct 
nvme_ns,
-                       siblings);
-       if (ns)
-               return ns;
+       if (ns) {
+               ns = list_next_or_null_rcu(&head->list, &ns->siblings,
+                                          struct nvme_ns, siblings);
+               if (ns)
+                       return ns;
+       }
         return list_first_or_null_rcu(&head->list, struct nvme_ns, 
siblings);
  }

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare at suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 N?rnberg
HRB 36809 (AG N?rnberg), Gesch?ftsf?hrer: Felix Imend?rffer


From mwilck at suse.com  Fri Jan 29 06:18:05 2021
From: mwilck at suse.com (Martin Wilck)
Date: Fri, 29 Jan 2021 12:18:05 +0100
Subject: [PATCH 00/35] RFC: add "nvme monitor" subcommand
In-Reply-To: <60846bb5-c0df-ac23-260b-b53afd48f661@grimberg.me>
References: <20210126203324.23610-1-mwilck@suse.com>
 <60846bb5-c0df-ac23-260b-b53afd48f661@grimberg.me>
Message-ID: <d8956cf973867ad7cc6c4d968682ec3db3054aa3.camel@suse.com>

On Thu, 2021-01-28 at 17:14 -0800, Sagi Grimberg wrote:
> 
> > From: Martin Wilck <mwilck at suse.com>
> > 
> > (Cover letter copied from 
> > https://github.com/linux-nvme/nvme-cli/pull/877)
> > 
> > This patch set adds a new subcommand **nvme monitor**. In this
> > mode,
> > **nvme-cli** runs continuously, monitors events (currently,
> > uevents) relevant
> > for discovery, and optionally autoconnects to newly discovered
> > subsystems.
> > 
> > The monitor mode is suitable to be run in a systemd service. An
> > appropriate
> > unit file is provided. As such, **nvme monitor** can be used as an
> > alternative
> > to the current auto-connection mechanism based on udev rules and
> > systemd
> > template units. If `--autoconnect` is active, **nvme monitor**
> > masks the
> > respective udev rules in order to prevent simultaneous connection
> > attempts
> > from udev and itself.
> 
> I think that a monitor daemon is a good path forward.
> 
> > 
> > This method for discovery and autodetection has some advantages
> > over the
> > current udev-rule based approach:
> > 
> > ? * By using the `--persistent` option, users can easily control
> > whether
> > ??? persistent discovery controllers for discovered transport
> > addresses should
> > ??? be created and monitored for AEN events. **nvme monitor**
> > watches known
> > ??? transport addresses, creates discovery controllers as required,
> > and re-uses
> > ??? existing ones if possible.
> 
> What does that mean?

In general, if the monitor detects a new host_traddr/traddr/trsvcid
tuple, it runs a discovery on it, and keeps the discovery controller
open if?--persistent was given. On startup, it scans existing
controllers, and if it finds already existing discovery controllers,
re-uses them. These will not be shut down when the monitor exits.

This allows users fine-grained control about what discovery controllers
to operate persistently. Users who want all discovery controllers to be
persistent just use --persistent. Others can set up those that they
want to have (manually or with a script), and not use --persistent.

The background is that hosts may not need every detected discovery
controller to be persistent. In multipath scenarios, you may see more
discovery subsystems than anything else, and not everyone likes that.
That's a generic issue and unrelated to the monitor, but running the
monitor with --persistent creates discovery controllers that would
otherwise not be visible.

Hope this clarifies it.

> > ? * In certain situations, the systemd-based approach may miss
> > events due to
> > ??? race conditions. This can happen e.g. if an FC remote port is
> > detected, but
> > ??? shortly after it's detection an FC relogin procedure is
> > necessary e.g. due to
> > ??? an RSCN. In this case, an `fc_udev_device` uevent will be
> > received on the
> > ??? first detection and handled by an `nvme connect-all` command
> > run from
> > ??? `nvmf-connect at .service`. The connection attempt to the rport in
> > question will
> > ??? fail with "no such device" because of the simultaneous FC
> > ??? relogin. `nvmf-connect at .service` may not terminate immediately,
> > because it
> > ??? attempts to establish other connections listed in the Discovery
> > Log page it
> > ??? retrieved. When the FC relogin eventually finishes, a new
> > uevent will be
> > ??? received, and `nvmf-connect@` will be started again, but *this
> > has no effect*
> > ??? if the previous `nvmf-connect@` service hasn't finished yet.
> > This is the
> > ??? general semantics of systemd services, no easy workaround
> > exists.? **nvme
> > ??? monitor** doesn't suffer from this problem. If it sees an
> > uevent for a
> > ??? transport address for which a discovery is already running, it
> > will queue the
> > ??? handling of this event up and restart the discovery after it's
> > finished.
> 
> While I understand the issue, this reason alone is an overkill for
> doing 
> this.

I agree. But it's not easy to fix the issue otherwise. In the customer
problem where we observed it, I worked around it by adding the udev
seqnum to the "instance name" of the systemd service, thus allowing
several "nvme connect-all" processes to run for the same transport
address simultaneously. But I don't think that would scale well;
the monitor can handle it more cleanly.

> > ? * Resource consumption for handling uevents is lower. Instead of
> > running an
> > ??? udev worker, executing the rules, executing `systemctl start`
> > from the
> > ??? worker, starting a systemd service, and starting a separate
> > **nvme-cli**
> > ??? instance, only a single `fork()` operation is necessary. Of
> > course, on the
> > ??? back side, the monitor itself consumes resources while it's
> > running and
> > ??? waiting for events. On my system with 8 persistent discovery
> > controllers,
> > ??? its RSS is ~3MB. CPU consumption is zero as long as no events
> > occur.
> 
> What is the baseline with what we have today?

A meaningful comparsion is difficult and should be done when the
monitor functionality is finalized. I made this statement only to
provide a rough idea of the resource usage, not more.

> > ? * **nvme monitor** could be easily extended to handle events for
> > non-FC
> > ??? transports.
> 
> Which events?

Network discovery, mDNS or the like. I haven't digged into the details
yet.

> > I've tested `fc_udev_device` handling for NVMeoFC with an Ontap
> > target, and
> > AEN handling for RDMA using a Linux **nvmet** target.
> > 
> > ### Implementation notes
> > 
> > I've tried to change the exisiting **nvme-cli** code as little as
> > possible
> > while reusing the code from `fabrics.c`. The majority of changes in
> > the
> > existing code exports formerly static functions and variables, so
> > that they
> > are usable from the monitor code.
> 
> General comment, can you please separate out fixes/cleanups that are
> not
> related to the goal of this patchset?

Which ones are you referring to? 09 and 19? While these are minor
improvements to the existing code, I wouldn't say they qualify as fixes
or cleanups. They aren't necessary without adding the monitor code.

But yes, I can post all changes to existing code separately.

> > ? *? When "add" uevents for nvme controller devices are received,
> > the
> > ???? controller is consistently not in `live` state yet, and
> > attempting to read
> > ???? the `subsysnqn` sysfs attribute returns `(efault)`. While this
> > should
> > ???? arguably be fixed in the kernel, it could be worked around in
> > user space
> > ???? by using timers or polling the `state` sysfs attribute for
> > changes.
> 
> This is a bug, what in the code causes this? nothing in controller
> state
> should prevent from this sysfs read from executing correctly...

I think it can be fixed by making nvme_sysfs_show_subsysnqn() fall back
to ctrl->opts->subsysnqn if ctrl->subsys is NULL.

I'll send a patch. Anyway, it'll take time until this is fixed
everywhere.

> 
> > ? * Parse and handle `discovery.conf` on startup.
> 
> This is a must I think, where do you get the known transport
> addresses
> on startup today?

There's a systemd service that runs "nvme connect-all" once during
boot. That exists today. I'm not sure if it should be integrated in the
monitor, perhaps it's good to keep these separate. People who don't
need the monitor can still run the existing service only, whereas for
others, the two would play together just fine.

> 
> > ? * Implement support for RDMA and TCP protocols.
> 
> What is needed for supporting them? Not sure I follow (I thought
> you mentioned that you tested against linux nvmet-rdma?)
> 

AENs over existing discovery controllers are supported for all
transports. But there's no support for discovery of new transports
except for NVMeoFC's "fc_udev_device" mechanism.

Regards
Martin






From mwilck at suse.com  Fri Jan 29 09:16:40 2021
From: mwilck at suse.com (Martin Wilck)
Date: Fri, 29 Jan 2021 15:16:40 +0100
Subject: [PATCH 13/35] monitor: disable nvmf-autoconnect udev rules in
 autoconnect mode
In-Reply-To: <8990bb65-fb2d-7ab1-82cd-210c4c4dba13@grimberg.me>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-14-mwilck@suse.com>
 <8990bb65-fb2d-7ab1-82cd-210c4c4dba13@grimberg.me>
Message-ID: <f6d3cc4105475207eab760d1d2e1c1693f3c3e16.camel@suse.com>

On Thu, 2021-01-28 at 17:52 -0800, Sagi Grimberg wrote:
> 
> 
> On 1/26/21 12:33 PM, mwilck at suse.com?wrote:
> > From: Martin Wilck <mwilck at suse.com>
> > 
> > If autoconnect is enabled, disable the respective udev rules
> > by symlinking /run/udev/rules.d to /dev/null, in order to avoid
> > the connections being set up by the monitor and the udev workers
> > at the same time. This is probably the preferred mode of operation
> > for the monitor.
> > 
> > Users can override this by copying 70-nvmf-autoconnect.rules
> > from /usr/lib/udev/rules.d to /etc/udev/rules.d (/etc/udev/rules.d
> > takes precedence over /run/udev/rules.d).
> > 
> > If the symlink can't be created for some reason, autoconnect will
> > be disabled. There is? only one exception: If
> > /run/udev/rules.d/70-nvmf-autoconnect.rules already points to
> > /dev/null at startup, autoconnect can be left on, but the symlink
> > isn't removed on exit.
> 
> Can't we just document that just one should be enabled and skip
> the entire thing? Especially when its not critical if both run..

It's not critical, but it makes no sense to have the rules enabled when
the monitor runs. And having to mask/unmask them manually is a pain.?

It could be done in the systemd service file using ExecStartPre /
ExecStopPost, with small restrictions (we couldn't distinguish whether
the rules were already masked before we started). That would be more
transparent for users.

I'm ok with not doing it automatically if that's generally preferred.

Regards
Martin






From mwilck at suse.com  Fri Jan 29 09:18:06 2021
From: mwilck at suse.com (Martin Wilck)
Date: Fri, 29 Jan 2021 15:18:06 +0100
Subject: [PATCH 22/35] conn-db: add simple connection registry
In-Reply-To: <322b27a0-ff3e-265b-4c69-fae54466631e@grimberg.me>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-23-mwilck@suse.com>
 <322b27a0-ff3e-265b-4c69-fae54466631e@grimberg.me>
Message-ID: <292a1b5ddd336c446ae63c06ee275af165c81ebc.camel@suse.com>

On Thu, 2021-01-28 at 17:59 -0800, Sagi Grimberg wrote:
> 
> > From: Martin Wilck <mwilck at suse.com>
> > 
> > The monitor works best if it maintains a discovery controller
> > connection
> > to every transport address that provides a discovery subsystem.
> > 
> > While controllers are easily tracked in sysfs, addresses
> > ("connections"),
> > i.e. (transport, traddr, trsvid, host_traddr) tuples, are not.
> > Create
> > a simple registry that tracks the state of "connections" and their
> > associated discovery controllers.
> > 
> > A detailed description of the API is provided in the header file
> > conn-db.h.
> 
> If this is more flexible, perhaps also the main fabrics 
> discover/connect/connect-all can be converted to use it as well.
> 

Yes. Could we do that in a separate step later.

Regards,
Martin







From mwilck at suse.com  Fri Jan 29 09:18:49 2021
From: mwilck at suse.com (Martin Wilck)
Date: Fri, 29 Jan 2021 15:18:49 +0100
Subject: [PATCH 16/35] monitor: reset children's signal disposition
In-Reply-To: <35ef1b10-1d24-f0f3-3af8-2d14d710533c@grimberg.me>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-17-mwilck@suse.com>
 <35ef1b10-1d24-f0f3-3af8-2d14d710533c@grimberg.me>
Message-ID: <6abf2fd0c4e04b3c11cb5240068200018449309c.camel@suse.com>

On Thu, 2021-01-28 at 17:54 -0800, Sagi Grimberg wrote:
> No commit message?

I'm sorry. I'll add one next time. For #17 likewise.

Martin




From sashal at kernel.org  Fri Jan 29 10:36:53 2021
From: sashal at kernel.org (Sasha Levin)
Date: Fri, 29 Jan 2021 10:36:53 -0500
Subject: [PATCH AUTOSEL 5.10 22/41] nvme: check the PRINFO bit before deciding
 the host buffer length
In-Reply-To: <20210129153713.1592185-1-sashal@kernel.org>
References: <20210129153713.1592185-1-sashal@kernel.org>
Message-ID: <20210129153713.1592185-22-sashal@kernel.org>

From: Revanth Rajashekar <revanth.rajashekar at intel.com>

[ Upstream commit 4d6b1c95b974761c01cbad92321b82232b66d2a2 ]

According to NVMe spec v1.4, section 8.3.1, the PRINFO bit and
the metadata size play a vital role in deteriming the host buffer size.

If PRIFNO bit is set and MS==8, the host doesn't add the metadata buffer,
instead the controller adds it.

Signed-off-by: Revanth Rajashekar <revanth.rajashekar at intel.com>
Signed-off-by: Christoph Hellwig <hch at lst.de>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/nvme/host/core.c | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 34cb59b2fcd67..4ec5f05dabe1d 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -1489,8 +1489,21 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
 	}
 
 	length = (io.nblocks + 1) << ns->lba_shift;
-	meta_len = (io.nblocks + 1) * ns->ms;
-	metadata = nvme_to_user_ptr(io.metadata);
+
+	if ((io.control & NVME_RW_PRINFO_PRACT) &&
+	    ns->ms == sizeof(struct t10_pi_tuple)) {
+		/*
+		 * Protection information is stripped/inserted by the
+		 * controller.
+		 */
+		if (nvme_to_user_ptr(io.metadata))
+			return -EINVAL;
+		meta_len = 0;
+		metadata = NULL;
+	} else {
+		meta_len = (io.nblocks + 1) * ns->ms;
+		metadata = nvme_to_user_ptr(io.metadata);
+	}
 
 	if (ns->features & NVME_NS_EXT_LBAS) {
 		length += meta_len;
-- 
2.27.0



From sashal at kernel.org  Fri Jan 29 10:36:54 2021
From: sashal at kernel.org (Sasha Levin)
Date: Fri, 29 Jan 2021 10:36:54 -0500
Subject: [PATCH AUTOSEL 5.10 23/41] nvme-rdma: avoid request double completion
 for concurrent nvme_rdma_timeout
In-Reply-To: <20210129153713.1592185-1-sashal@kernel.org>
References: <20210129153713.1592185-1-sashal@kernel.org>
Message-ID: <20210129153713.1592185-23-sashal@kernel.org>

From: Chao Leng <lengchao at huawei.com>

[ Upstream commit 7674073b2ed35ac951a49c425dec6b39d5a57140 ]

A crash happens when inject completing request long time(nearly 30s).
Each name space has a request queue, when inject completing request long
time, multi request queues may have time out requests at the same time,
nvme_rdma_timeout will execute concurrently. Multi requests in different
request queues may be queued in the same rdma queue, multi
nvme_rdma_timeout may call nvme_rdma_stop_queue at the same time.
The first nvme_rdma_timeout will clear NVME_RDMA_Q_LIVE and continue
stopping the rdma queue(drain qp), but the others check NVME_RDMA_Q_LIVE
is already cleared, and then directly complete the requests, complete
request before the qp is fully drained may lead to a use-after-free
condition.

Add a multex lock to serialize nvme_rdma_stop_queue.

Signed-off-by: Chao Leng <lengchao at huawei.com>
Tested-by: Israel Rukshin <israelr at nvidia.com>
Reviewed-by: Israel Rukshin <israelr at nvidia.com>
Signed-off-by: Christoph Hellwig <hch at lst.de>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/nvme/host/rdma.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index 65e3d0ef36e1a..493ed7ba86ed2 100644
--- a/drivers/nvme/host/rdma.c
+++ b/drivers/nvme/host/rdma.c
@@ -97,6 +97,7 @@ struct nvme_rdma_queue {
 	struct completion	cm_done;
 	bool			pi_support;
 	int			cq_size;
+	struct mutex		queue_lock;
 };
 
 struct nvme_rdma_ctrl {
@@ -579,6 +580,7 @@ static int nvme_rdma_alloc_queue(struct nvme_rdma_ctrl *ctrl,
 	int ret;
 
 	queue = &ctrl->queues[idx];
+	mutex_init(&queue->queue_lock);
 	queue->ctrl = ctrl;
 	if (idx && ctrl->ctrl.max_integrity_segments)
 		queue->pi_support = true;
@@ -598,7 +600,8 @@ static int nvme_rdma_alloc_queue(struct nvme_rdma_ctrl *ctrl,
 	if (IS_ERR(queue->cm_id)) {
 		dev_info(ctrl->ctrl.device,
 			"failed to create CM ID: %ld\n", PTR_ERR(queue->cm_id));
-		return PTR_ERR(queue->cm_id);
+		ret = PTR_ERR(queue->cm_id);
+		goto out_destroy_mutex;
 	}
 
 	if (ctrl->ctrl.opts->mask & NVMF_OPT_HOST_TRADDR)
@@ -628,6 +631,8 @@ static int nvme_rdma_alloc_queue(struct nvme_rdma_ctrl *ctrl,
 out_destroy_cm_id:
 	rdma_destroy_id(queue->cm_id);
 	nvme_rdma_destroy_queue_ib(queue);
+out_destroy_mutex:
+	mutex_destroy(&queue->queue_lock);
 	return ret;
 }
 
@@ -639,9 +644,10 @@ static void __nvme_rdma_stop_queue(struct nvme_rdma_queue *queue)
 
 static void nvme_rdma_stop_queue(struct nvme_rdma_queue *queue)
 {
-	if (!test_and_clear_bit(NVME_RDMA_Q_LIVE, &queue->flags))
-		return;
-	__nvme_rdma_stop_queue(queue);
+	mutex_lock(&queue->queue_lock);
+	if (test_and_clear_bit(NVME_RDMA_Q_LIVE, &queue->flags))
+		__nvme_rdma_stop_queue(queue);
+	mutex_unlock(&queue->queue_lock);
 }
 
 static void nvme_rdma_free_queue(struct nvme_rdma_queue *queue)
@@ -651,6 +657,7 @@ static void nvme_rdma_free_queue(struct nvme_rdma_queue *queue)
 
 	nvme_rdma_destroy_queue_ib(queue);
 	rdma_destroy_id(queue->cm_id);
+	mutex_destroy(&queue->queue_lock);
 }
 
 static void nvme_rdma_free_io_queues(struct nvme_rdma_ctrl *ctrl)
-- 
2.27.0



From sashal at kernel.org  Fri Jan 29 10:36:55 2021
From: sashal at kernel.org (Sasha Levin)
Date: Fri, 29 Jan 2021 10:36:55 -0500
Subject: [PATCH AUTOSEL 5.10 24/41] nvme-tcp: avoid request double completion
 for concurrent nvme_tcp_timeout
In-Reply-To: <20210129153713.1592185-1-sashal@kernel.org>
References: <20210129153713.1592185-1-sashal@kernel.org>
Message-ID: <20210129153713.1592185-24-sashal@kernel.org>

From: Chao Leng <lengchao at huawei.com>

[ Upstream commit 9ebbfe495ecd2e51bc92ac21ed5817c3b9e223ce ]

Each name space has a request queue, if complete request long time,
multi request queues may have time out requests at the same time,
nvme_tcp_timeout will execute concurrently. Multi requests in different
request queues may be queued in the same tcp queue, multi
nvme_tcp_timeout may call nvme_tcp_stop_queue at the same time.
The first nvme_tcp_stop_queue will clear NVME_TCP_Q_LIVE and continue
stopping the tcp queue(cancel io_work), but the others check
NVME_TCP_Q_LIVE is already cleared, and then directly complete the
requests, complete request before the io work is completely canceled may
lead to a use-after-free condition.
Add a multex lock to serialize nvme_tcp_stop_queue.

Signed-off-by: Chao Leng <lengchao at huawei.com>
Signed-off-by: Christoph Hellwig <hch at lst.de>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/nvme/host/tcp.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 81db2331f6d78..6487b7897d1fb 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -76,6 +76,7 @@ struct nvme_tcp_queue {
 	struct work_struct	io_work;
 	int			io_cpu;
 
+	struct mutex		queue_lock;
 	struct mutex		send_mutex;
 	struct llist_head	req_list;
 	struct list_head	send_list;
@@ -1219,6 +1220,7 @@ static void nvme_tcp_free_queue(struct nvme_ctrl *nctrl, int qid)
 
 	sock_release(queue->sock);
 	kfree(queue->pdu);
+	mutex_destroy(&queue->queue_lock);
 }
 
 static int nvme_tcp_init_connection(struct nvme_tcp_queue *queue)
@@ -1380,6 +1382,7 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl,
 	struct nvme_tcp_queue *queue = &ctrl->queues[qid];
 	int ret, rcv_pdu_size;
 
+	mutex_init(&queue->queue_lock);
 	queue->ctrl = ctrl;
 	init_llist_head(&queue->req_list);
 	INIT_LIST_HEAD(&queue->send_list);
@@ -1398,7 +1401,7 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl,
 	if (ret) {
 		dev_err(nctrl->device,
 			"failed to create socket: %d\n", ret);
-		return ret;
+		goto err_destroy_mutex;
 	}
 
 	/* Single syn retry */
@@ -1507,6 +1510,8 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl,
 err_sock:
 	sock_release(queue->sock);
 	queue->sock = NULL;
+err_destroy_mutex:
+	mutex_destroy(&queue->queue_lock);
 	return ret;
 }
 
@@ -1534,9 +1539,10 @@ static void nvme_tcp_stop_queue(struct nvme_ctrl *nctrl, int qid)
 	struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl);
 	struct nvme_tcp_queue *queue = &ctrl->queues[qid];
 
-	if (!test_and_clear_bit(NVME_TCP_Q_LIVE, &queue->flags))
-		return;
-	__nvme_tcp_stop_queue(queue);
+	mutex_lock(&queue->queue_lock);
+	if (test_and_clear_bit(NVME_TCP_Q_LIVE, &queue->flags))
+		__nvme_tcp_stop_queue(queue);
+	mutex_unlock(&queue->queue_lock);
 }
 
 static int nvme_tcp_start_queue(struct nvme_ctrl *nctrl, int idx)
-- 
2.27.0



From sashal at kernel.org  Fri Jan 29 10:36:56 2021
From: sashal at kernel.org (Sasha Levin)
Date: Fri, 29 Jan 2021 10:36:56 -0500
Subject: [PATCH AUTOSEL 5.10 25/41] nvme-pci: allow use of cmb on v1.4
 controllers
In-Reply-To: <20210129153713.1592185-1-sashal@kernel.org>
References: <20210129153713.1592185-1-sashal@kernel.org>
Message-ID: <20210129153713.1592185-25-sashal@kernel.org>

From: Klaus Jensen <k.jensen at samsung.com>

[ Upstream commit 20d3bb92e84d417b0494a3b6867f0c86713db257 ]

Since NVMe v1.4 the Controller Memory Buffer must be explicitly enabled
by the host.

Signed-off-by: Klaus Jensen <k.jensen at samsung.com>
[hch: avoid a local variable and add a comment]
Signed-off-by: Christoph Hellwig <hch at lst.de>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/nvme/host/pci.c | 14 ++++++++++++++
 include/linux/nvme.h    |  6 ++++++
 2 files changed, 20 insertions(+)

diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 77f615568194d..a3486c1c27f0c 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -23,6 +23,7 @@
 #include <linux/t10-pi.h>
 #include <linux/types.h>
 #include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/io-64-nonatomic-hi-lo.h>
 #include <linux/sed-opal.h>
 #include <linux/pci-p2pdma.h>
 
@@ -1825,6 +1826,9 @@ static void nvme_map_cmb(struct nvme_dev *dev)
 	if (dev->cmb_size)
 		return;
 
+	if (NVME_CAP_CMBS(dev->ctrl.cap))
+		writel(NVME_CMBMSC_CRE, dev->bar + NVME_REG_CMBMSC);
+
 	dev->cmbsz = readl(dev->bar + NVME_REG_CMBSZ);
 	if (!dev->cmbsz)
 		return;
@@ -1838,6 +1842,16 @@ static void nvme_map_cmb(struct nvme_dev *dev)
 	if (offset > bar_size)
 		return;
 
+	/*
+	 * Tell the controller about the host side address mapping the CMB,
+	 * and enable CMB decoding for the NVMe 1.4+ scheme:
+	 */
+	if (NVME_CAP_CMBS(dev->ctrl.cap)) {
+		hi_lo_writeq(NVME_CMBMSC_CRE | NVME_CMBMSC_CMSE |
+			     (pci_bus_address(pdev, bar) + offset),
+			     dev->bar + NVME_REG_CMBMSC);
+	}
+
 	/*
 	 * Controllers may support a CMB size larger than their BAR,
 	 * for example, due to being behind a bridge. Reduce the CMB to
diff --git a/include/linux/nvme.h b/include/linux/nvme.h
index d925359976873..bfed36e342ccb 100644
--- a/include/linux/nvme.h
+++ b/include/linux/nvme.h
@@ -116,6 +116,9 @@ enum {
 	NVME_REG_BPMBL	= 0x0048,	/* Boot Partition Memory Buffer
 					 * Location
 					 */
+	NVME_REG_CMBMSC = 0x0050,	/* Controller Memory Buffer Memory
+					 * Space Control
+					 */
 	NVME_REG_PMRCAP	= 0x0e00,	/* Persistent Memory Capabilities */
 	NVME_REG_PMRCTL	= 0x0e04,	/* Persistent Memory Region Control */
 	NVME_REG_PMRSTS	= 0x0e08,	/* Persistent Memory Region Status */
@@ -135,6 +138,7 @@ enum {
 #define NVME_CAP_CSS(cap)	(((cap) >> 37) & 0xff)
 #define NVME_CAP_MPSMIN(cap)	(((cap) >> 48) & 0xf)
 #define NVME_CAP_MPSMAX(cap)	(((cap) >> 52) & 0xf)
+#define NVME_CAP_CMBS(cap)	(((cap) >> 57) & 0x1)
 
 #define NVME_CMB_BIR(cmbloc)	((cmbloc) & 0x7)
 #define NVME_CMB_OFST(cmbloc)	(((cmbloc) >> 12) & 0xfffff)
@@ -192,6 +196,8 @@ enum {
 	NVME_CSTS_SHST_OCCUR	= 1 << 2,
 	NVME_CSTS_SHST_CMPLT	= 2 << 2,
 	NVME_CSTS_SHST_MASK	= 3 << 2,
+	NVME_CMBMSC_CRE		= 1 << 0,
+	NVME_CMBMSC_CMSE	= 1 << 1,
 };
 
 struct nvme_id_power_state {
-- 
2.27.0



From sashal at kernel.org  Fri Jan 29 10:36:57 2021
From: sashal at kernel.org (Sasha Levin)
Date: Fri, 29 Jan 2021 10:36:57 -0500
Subject: [PATCH AUTOSEL 5.10 26/41] nvmet: set right status on error in id-ns
 handler
In-Reply-To: <20210129153713.1592185-1-sashal@kernel.org>
References: <20210129153713.1592185-1-sashal@kernel.org>
Message-ID: <20210129153713.1592185-26-sashal@kernel.org>

From: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>

[ Upstream commit bffcd507780ea614b5543c66f2e37ce0d55cd449 ]

The function nvmet_execute_identify_ns() doesn't set the status if call
to nvmet_find_namespace() fails. In that case we set the status of the
request to the value return by the nvmet_copy_sgl().

Set the status to NVME_SC_INVALID_NS and adjust the code such that
request will have the right status on nvmet_find_namespace() failure.

Without this patch :-
NVME Identify Namespace 3:
nsze    : 0
ncap    : 0
nuse    : 0
nsfeat  : 0
nlbaf   : 0
flbas   : 0
mc      : 0
dpc     : 0
dps     : 0
nmic    : 0
rescap  : 0
fpi     : 0
dlfeat  : 0
nawun   : 0
nawupf  : 0
nacwu   : 0
nabsn   : 0
nabo    : 0
nabspf  : 0
noiob   : 0
nvmcap  : 0
mssrl   : 0
mcl     : 0
msrc    : 0
nsattr	: 0
nvmsetid: 0
anagrpid: 0
endgid  : 0
nguid   : 00000000000000000000000000000000
eui64   : 0000000000000000
lbaf  0 : ms:0   lbads:0  rp:0 (in use)

With this patch-series :-
feb3b88b501e (HEAD -> nvme-5.11) nvmet: remove extra variable in identify ns
6302aa67210a nvmet: remove extra variable in id-desclist
ed57951da453 nvmet: remove extra variable in smart log nsid
be384b8c24dc nvmet: set right status on error in id-ns handler

NVMe status: INVALID_NS: The namespace or the format of that namespace is invalid(0xb)

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
Reviewed-by: Sagi Grimberg <sagi at grimberg.me>
Signed-off-by: Christoph Hellwig <hch at lst.de>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/nvme/target/admin-cmd.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index dca34489a1dc9..92ca23bc8dbfc 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -487,8 +487,10 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req)
 
 	/* return an all zeroed buffer if we can't find an active namespace */
 	ns = nvmet_find_namespace(ctrl, req->cmd->identify.nsid);
-	if (!ns)
+	if (!ns) {
+		status = NVME_SC_INVALID_NS;
 		goto done;
+	}
 
 	nvmet_ns_revalidate(ns);
 
@@ -541,7 +543,9 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req)
 		id->nsattr |= (1 << 0);
 	nvmet_put_namespace(ns);
 done:
-	status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id));
+	if (!status)
+		status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id));
+
 	kfree(id);
 out:
 	nvmet_req_complete(req, status);
-- 
2.27.0



From sashal at kernel.org  Fri Jan 29 10:38:00 2021
From: sashal at kernel.org (Sasha Levin)
Date: Fri, 29 Jan 2021 10:38:00 -0500
Subject: [PATCH AUTOSEL 5.4 13/19] nvme: check the PRINFO bit before deciding
 the host buffer length
In-Reply-To: <20210129153806.1592565-1-sashal@kernel.org>
References: <20210129153806.1592565-1-sashal@kernel.org>
Message-ID: <20210129153806.1592565-13-sashal@kernel.org>

From: Revanth Rajashekar <revanth.rajashekar at intel.com>

[ Upstream commit 4d6b1c95b974761c01cbad92321b82232b66d2a2 ]

According to NVMe spec v1.4, section 8.3.1, the PRINFO bit and
the metadata size play a vital role in deteriming the host buffer size.

If PRIFNO bit is set and MS==8, the host doesn't add the metadata buffer,
instead the controller adds it.

Signed-off-by: Revanth Rajashekar <revanth.rajashekar at intel.com>
Signed-off-by: Christoph Hellwig <hch at lst.de>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/nvme/host/core.c | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 7a964271959d8..c2cabd77884bf 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -1295,8 +1295,21 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
 	}
 
 	length = (io.nblocks + 1) << ns->lba_shift;
-	meta_len = (io.nblocks + 1) * ns->ms;
-	metadata = nvme_to_user_ptr(io.metadata);
+
+	if ((io.control & NVME_RW_PRINFO_PRACT) &&
+	    ns->ms == sizeof(struct t10_pi_tuple)) {
+		/*
+		 * Protection information is stripped/inserted by the
+		 * controller.
+		 */
+		if (nvme_to_user_ptr(io.metadata))
+			return -EINVAL;
+		meta_len = 0;
+		metadata = NULL;
+	} else {
+		meta_len = (io.nblocks + 1) * ns->ms;
+		metadata = nvme_to_user_ptr(io.metadata);
+	}
 
 	if (ns->ext) {
 		length += meta_len;
-- 
2.27.0



From sagi at grimberg.me  Fri Jan 29 13:54:03 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Fri, 29 Jan 2021 10:54:03 -0800
Subject: [PATCH 13/35] monitor: disable nvmf-autoconnect udev rules in
 autoconnect mode
In-Reply-To: <f6d3cc4105475207eab760d1d2e1c1693f3c3e16.camel@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-14-mwilck@suse.com>
 <8990bb65-fb2d-7ab1-82cd-210c4c4dba13@grimberg.me>
 <f6d3cc4105475207eab760d1d2e1c1693f3c3e16.camel@suse.com>
Message-ID: <c8f2138f-be9f-41b3-2fb9-083ed65927d7@grimberg.me>


>> On 1/26/21 12:33 PM, mwilck at suse.com?wrote:
>>> From: Martin Wilck <mwilck at suse.com>
>>>
>>> If autoconnect is enabled, disable the respective udev rules
>>> by symlinking /run/udev/rules.d to /dev/null, in order to avoid
>>> the connections being set up by the monitor and the udev workers
>>> at the same time. This is probably the preferred mode of operation
>>> for the monitor.
>>>
>>> Users can override this by copying 70-nvmf-autoconnect.rules
>>> from /usr/lib/udev/rules.d to /etc/udev/rules.d (/etc/udev/rules.d
>>> takes precedence over /run/udev/rules.d).
>>>
>>> If the symlink can't be created for some reason, autoconnect will
>>> be disabled. There is? only one exception: If
>>> /run/udev/rules.d/70-nvmf-autoconnect.rules already points to
>>> /dev/null at startup, autoconnect can be left on, but the symlink
>>> isn't removed on exit.
>>
>> Can't we just document that just one should be enabled and skip
>> the entire thing? Especially when its not critical if both run..
> 
> It's not critical, but it makes no sense to have the rules enabled when
> the monitor runs. And having to mask/unmask them manually is a pain.
> 
> It could be done in the systemd service file using ExecStartPre /
> ExecStopPost, with small restrictions (we couldn't distinguish whether
> the rules were already masked before we started). That would be more
> transparent for users.

Maybe 'Conflicts' can help here?


From sagi at grimberg.me  Fri Jan 29 13:59:20 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Fri, 29 Jan 2021 10:59:20 -0800
Subject: [PATCH 11/35] monitor: add option -A / --autoconnect
In-Reply-To: <20210126203324.23610-12-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-12-mwilck@suse.com>
Message-ID: <d9c74675-a324-b863-1dee-454fc90d5e77@grimberg.me>


> With this option, the monitor will try to connect to newly discovered
> controllers.

Maybe I'm missing something here, but what does it do without
autoconnect?


From sagi at grimberg.me  Fri Jan 29 14:02:51 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Fri, 29 Jan 2021 11:02:51 -0800
Subject: [PATCH 18/35] monitor: add "--persistent/-p" flag
In-Reply-To: <20210126203324.23610-19-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-19-mwilck@suse.com>
Message-ID: <6d6104c8-708f-d09c-7b5e-5bcd6bddf223@grimberg.me>


> Without this flag, AENs on created controllers won't be received.
> While --persistent is probably the behavior most users will want,
> it has to be explicitly activated, to be consistent with the
> connect-all command.

What is the usage model without this flag?


From sagi at grimberg.me  Fri Jan 29 14:08:54 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Fri, 29 Jan 2021 11:08:54 -0800
Subject: [PATCH 32/35] nvmf-autoconnect: add unit file for
 nvme-monitor.service
In-Reply-To: <20210126203324.23610-33-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-33-mwilck@suse.com>
Message-ID: <0aaeb938-4d72-f138-6e24-0a7f95d05b39@grimberg.me>


> Signed-off-by: Martin Wilck <mwilck at suse.com>
> ---
>   nvmf-autoconnect/systemd/nvme-monitor.service | 17 +++++++++++++++++
>   1 file changed, 17 insertions(+)
>   create mode 100644 nvmf-autoconnect/systemd/nvme-monitor.service
> 
> diff --git a/nvmf-autoconnect/systemd/nvme-monitor.service b/nvmf-autoconnect/systemd/nvme-monitor.service
> new file mode 100644
> index 0000000..d85b133
> --- /dev/null
> +++ b/nvmf-autoconnect/systemd/nvme-monitor.service
> @@ -0,0 +1,17 @@
> +[Unit]
> +Description=NVMe Event Monitor for Automatical Subsystem Connection
> +Documentation=man:nvme-monitor(1)
> +DefaultDependencies=false
> +Requires=systemd-udevd-kernel.socket
> +RequiresMountsFor=/sys
> +Conflicts=shutdown.target
> +After=systemd-udevd-kernel.socket
> +Before=sysinit.target systemd-udev-trigger.service nvmefc-boot-connections.service
> +
> +[Service]
> +Type=simple
> +ExecStart=/usr/sbin/nvme monitor -A -p

I've seen issues with assuming nvme sits in /usr/sbin/


From sagi at grimberg.me  Fri Jan 29 14:09:12 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Fri, 29 Jan 2021 11:09:12 -0800
Subject: [PATCH 33/35] nvme-connect-all(1): fix documentation for
 --quiet/-S
In-Reply-To: <20210126203324.23610-34-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-34-mwilck@suse.com>
Message-ID: <ad90839a-f4a1-d8be-9dbc-58f839c7560d@grimberg.me>

Cleanup unrelated patch

On 1/26/21 12:33 PM, mwilck at suse.com wrote:
> From: Martin Wilck <mwilck at suse.com>
> 
> Signed-off-by: Martin Wilck <mwilck at suse.com>
> ---
>   Documentation/nvme-connect-all.1    |  8 ++++----
>   Documentation/nvme-connect-all.html | 10 +++++-----
>   Documentation/nvme-connect-all.txt  |  4 ++--
>   3 files changed, 11 insertions(+), 11 deletions(-)
> 
> diff --git a/Documentation/nvme-connect-all.1 b/Documentation/nvme-connect-all.1
> index 91d6896..a53a017 100644
> --- a/Documentation/nvme-connect-all.1
> +++ b/Documentation/nvme-connect-all.1
> @@ -2,12 +2,12 @@
>   .\"     Title: nvme-connect-all
>   .\"    Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
>   .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
> -.\"      Date: 10/20/2020
> +.\"      Date: 01/20/2021
>   .\"    Manual: NVMe Manual
>   .\"    Source: NVMe
>   .\"  Language: English
>   .\"
> -.TH "NVME\-CONNECT\-ALL" "1" "10/20/2020" "NVMe" "NVMe Manual"
> +.TH "NVME\-CONNECT\-ALL" "1" "01/20/2021" "NVMe" "NVMe Manual"
>   .\" -----------------------------------------------------------------
>   .\" * Define some portability stuff
>   .\" -----------------------------------------------------------------
> @@ -51,7 +51,7 @@ nvme-connect-all \- Discover and Connect to Fabrics controllers\&.
>                   [\-\-queue\-size=<#>         | \-Q <#>]
>                   [\-\-matching               | \-m]
>                   [\-\-persistent             | \-p]
> -                [\-\-quiet                  | \-q]
> +                [\-\-quiet                  | \-S]
>   .fi
>   .SH "DESCRIPTION"
>   .sp
> @@ -193,7 +193,7 @@ If a traddr was specified on the command line or in the configuration file, only
>   Don\(cqt remove the discovery controller after retrieving the discovery log page\&.
>   .RE
>   .PP
> -\-q, \-\-quiet
> +\-S, \-\-quiet
>   .RS 4
>   Suppress error messages\&.
>   .RE
> diff --git a/Documentation/nvme-connect-all.html b/Documentation/nvme-connect-all.html
> index beae013..f779c7b 100644
> --- a/Documentation/nvme-connect-all.html
> +++ b/Documentation/nvme-connect-all.html
> @@ -4,7 +4,7 @@
>   <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
>   <head>
>   <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
> -<meta name="generator" content="AsciiDoc 8.6.10" />
> +<meta name="generator" content="AsciiDoc" />
>   <title>nvme-connect-all(1)</title>
>   <style type="text/css">
>   /* Shared CSS for AsciiDoc xhtml11 and html5 backends */
> @@ -436,7 +436,7 @@ thead, p.table.header {
>   p.table {
>     margin-top: 0;
>   }
> -/* Because the table frame attribute is overriden by CSS in most browsers. */
> +/* Because the table frame attribute is overridden by CSS in most browsers. */
>   div.tableblock > table[frame="void"] {
>     border-style: none;
>   }
> @@ -768,7 +768,7 @@ nvme-connect-all(1) Manual Page
>                   [--queue-size=&lt;#&gt;         | -Q &lt;#&gt;]
>                   [--matching               | -m]
>                   [--persistent             | -p]
> -                [--quiet                  | -q]</pre>
> +                [--quiet                  | -S]</pre>
>   <div class="attribution">
>   </div></div>
>   </div>
> @@ -1048,7 +1048,7 @@ cellspacing="0" cellpadding="4">
>   </p>
>   </dd>
>   <dt class="hdlist1">
> --q
> +-S
>   </dt>
>   <dt class="hdlist1">
>   --quiet
> @@ -1115,7 +1115,7 @@ nvme-connect(1)</p></div>
>   <div id="footer">
>   <div id="footer-text">
>   Last updated
> - 2020-10-20 16:47:21 PDT
> + 2021-01-20 23:40:57 CET
>   </div>
>   </div>
>   </body>
> diff --git a/Documentation/nvme-connect-all.txt b/Documentation/nvme-connect-all.txt
> index 128f336..820dd6c 100644
> --- a/Documentation/nvme-connect-all.txt
> +++ b/Documentation/nvme-connect-all.txt
> @@ -27,7 +27,7 @@ SYNOPSIS
>   		[--queue-size=<#>         | -Q <#>]
>   		[--matching               | -m]
>   		[--persistent             | -p]
> -		[--quiet                  | -q]
> +		[--quiet                  | -S]
>   
>   DESCRIPTION
>   -----------
> @@ -154,7 +154,7 @@ OPTIONS
>   	Don't remove the discovery controller after retrieving the discovery
>   	log page.
>   
> --q::
> +-S::
>   --quiet::
>   	Suppress error messages.
>   
> 


From sagi at grimberg.me  Fri Jan 29 14:10:05 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Fri, 29 Jan 2021 11:10:05 -0800
Subject: [PATCH 35/35] monitor: add option --keep/-K
In-Reply-To: <20210126203324.23610-36-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-36-mwilck@suse.com>
Message-ID: <90145500-c2c5-023c-6d69-27db6ee600a7@grimberg.me>


> From: Martin Wilck <mwilck at suse.com>
> 
> With this option, "nvme monitor" will keep created discovery controllers
> running even after it exits. If running in the initrd, this is will be
> done automatically. That has the advantage that the new monitor instance
> that will be started automatically after switching root can simply take
> over the already created discovery controllers.

Why not make it the default?


From mwilck at suse.com  Fri Jan 29 14:33:30 2021
From: mwilck at suse.com (Martin Wilck)
Date: Fri, 29 Jan 2021 20:33:30 +0100
Subject: [PATCH 11/35] monitor: add option -A / --autoconnect
In-Reply-To: <d9c74675-a324-b863-1dee-454fc90d5e77@grimberg.me>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-12-mwilck@suse.com>
 <d9c74675-a324-b863-1dee-454fc90d5e77@grimberg.me>
Message-ID: <cbf4808b0becc3978b758d5be5cc3f3c1c6fe86f.camel@suse.com>

On Fri, 2021-01-29 at 10:59 -0800, Sagi Grimberg wrote:
> 
> > With this option, the monitor will try to connect to newly
> > discovered
> > controllers.
> 
> Maybe I'm missing something here, but what does it do without
> autoconnect?
> 

Basically it just runs "nvme discover". When events come in,
it runs the discovery and prints the results, like "discover" would.

We can change that of course.

Martin




From mwilck at suse.com  Fri Jan 29 14:45:41 2021
From: mwilck at suse.com (Martin Wilck)
Date: Fri, 29 Jan 2021 20:45:41 +0100
Subject: [PATCH 18/35] monitor: add "--persistent/-p" flag
In-Reply-To: <6d6104c8-708f-d09c-7b5e-5bcd6bddf223@grimberg.me>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-19-mwilck@suse.com>
 <6d6104c8-708f-d09c-7b5e-5bcd6bddf223@grimberg.me>
Message-ID: <fb3b5117db55ebb91b490d56b7817daafc5fc84e.camel@suse.com>

On Fri, 2021-01-29 at 11:02 -0800, Sagi Grimberg wrote:
> 
> > Without this flag, AENs on created controllers won't be received.
> > While --persistent is probably the behavior most users will want,
> > it has to be explicitly activated, to be consistent with the
> > connect-all command.
> 
> What is the usage model without this flag?
> 

 - listen to other events that would require a discovery, currently
simply fc_udev_device. In the future, network events could be added.
 - listen for AENs on persistent discovery controllers that are created
by other means, e.g. manually.
   
See also our discussion about the cover letter of this series.

Martin





From mwilck at suse.com  Fri Jan 29 14:50:01 2021
From: mwilck at suse.com (Martin Wilck)
Date: Fri, 29 Jan 2021 20:50:01 +0100
Subject: [PATCH 32/35] nvmf-autoconnect: add unit file for
 nvme-monitor.service
In-Reply-To: <0aaeb938-4d72-f138-6e24-0a7f95d05b39@grimberg.me>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-33-mwilck@suse.com>
 <0aaeb938-4d72-f138-6e24-0a7f95d05b39@grimberg.me>
Message-ID: <d699b37ac6951214aa91b28c87a51510197b3670.camel@suse.com>

On Fri, 2021-01-29 at 11:08 -0800, Sagi Grimberg wrote:
> 
> > Signed-off-by: Martin Wilck <mwilck at suse.com>
> > ---
> > ? nvmf-autoconnect/systemd/nvme-monitor.service | 17
> > +++++++++++++++++
> > ? 1 file changed, 17 insertions(+)
> > ? create mode 100644 nvmf-autoconnect/systemd/nvme-monitor.service
> > 
> > diff --git a/nvmf-autoconnect/systemd/nvme-monitor.service b/nvmf-
> > autoconnect/systemd/nvme-monitor.service
> > new file mode 100644
> > index 0000000..d85b133
> > --- /dev/null
> > +++ b/nvmf-autoconnect/systemd/nvme-monitor.service
> > @@ -0,0 +1,17 @@
> > +[Unit]
> > +Description=NVMe Event Monitor for Automatical Subsystem
> > Connection
> > +Documentation=man:nvme-monitor(1)
> > +DefaultDependencies=false
> > +Requires=systemd-udevd-kernel.socket
> > +RequiresMountsFor=/sys
> > +Conflicts=shutdown.target
> > +After=systemd-udevd-kernel.socket
> > +Before=sysinit.target systemd-udev-trigger.service nvmefc-boot-
> > connections.service
> > +
> > +[Service]
> > +Type=simple
> > +ExecStart=/usr/sbin/nvme monitor -A -p
> 
> I've seen issues with assuming nvme sits in /usr/sbin/

Sure, this can be fixed. More fine tuning is possible, too. I learned
meanwhile that the dependency on systemd-udevd-kernel.socket is
unnecessary.

Regards
Martin





From mwilck at suse.com  Fri Jan 29 14:53:38 2021
From: mwilck at suse.com (Martin Wilck)
Date: Fri, 29 Jan 2021 20:53:38 +0100
Subject: [PATCH 35/35] monitor: add option --keep/-K
In-Reply-To: <90145500-c2c5-023c-6d69-27db6ee600a7@grimberg.me>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-36-mwilck@suse.com>
 <90145500-c2c5-023c-6d69-27db6ee600a7@grimberg.me>
Message-ID: <12827c5f748bd2eff31450c47bbef1cfc7b73459.camel@suse.com>

On Fri, 2021-01-29 at 11:10 -0800, Sagi Grimberg wrote:
> 
> > From: Martin Wilck <mwilck at suse.com>
> > 
> > With this option, "nvme monitor" will keep created discovery
> > controllers
> > running even after it exits. If running in the initrd, this is will
> > be
> > done automatically. That has the advantage that the new monitor
> > instance
> > that will be started automatically after switching root can simply
> > take
> > over the already created discovery controllers.
> 
> Why not make it the default?

Well, we've had a lot of discussions about persistent discovery
connections not being universally loved. So I thought I'd make cleaning
up the default.

All this can be discussed of course, that's why I called it an RFC.

Martin






From sagi at grimberg.me  Fri Jan 29 15:08:08 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Fri, 29 Jan 2021 12:08:08 -0800
Subject: [PATCH 00/35] RFC: add "nvme monitor" subcommand
In-Reply-To: <d8956cf973867ad7cc6c4d968682ec3db3054aa3.camel@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
 <60846bb5-c0df-ac23-260b-b53afd48f661@grimberg.me>
 <d8956cf973867ad7cc6c4d968682ec3db3054aa3.camel@suse.com>
Message-ID: <d8e35845-31d3-a46d-b464-728d751d0b33@grimberg.me>


>>>
>>> This method for discovery and autodetection has some advantages
>>> over the
>>> current udev-rule based approach:
>>>
>>>  ? * By using the `--persistent` option, users can easily control
>>> whether
>>>  ??? persistent discovery controllers for discovered transport
>>> addresses should
>>>  ??? be created and monitored for AEN events. **nvme monitor**
>>> watches known
>>>  ??? transport addresses, creates discovery controllers as required,
>>> and re-uses
>>>  ??? existing ones if possible.
>>
>> What does that mean?
> 
> In general, if the monitor detects a new host_traddr/traddr/trsvcid
> tuple, it runs a discovery on it, and keeps the discovery controller
> open if?--persistent was given. On startup, it scans existing
> controllers, and if it finds already existing discovery controllers,
> re-uses them. These will not be shut down when the monitor exits.

And if it doesn't run with --persistent it deletes them? even if these
weren't created by it?

And, if none exist where does it get new discovery controller details?
Today we use discovery.conf for that.

> This allows users fine-grained control about what discovery controllers
> to operate persistently. Users who want all discovery controllers to be
> persistent just use --persistent. Others can set up those that they
> want to have (manually or with a script), and not use --persistent.
> 
> The background is that hosts may not need every detected discovery
> controller to be persistent. In multipath scenarios, you may see more
> discovery subsystems than anything else, and not everyone likes that.
> That's a generic issue and unrelated to the monitor, but running the
> monitor with --persistent creates discovery controllers that would
> otherwise not be visible.
> 
> Hope this clarifies it.

Well, How do people expect to know if stuff change without a persistent
discovery controller? Not sure if people may see more discovery
controllers this is a real issue given what they are getting from it.

But OK.

>>>  ? * In certain situations, the systemd-based approach may miss
>>> events due to
>>>  ??? race conditions. This can happen e.g. if an FC remote port is
>>> detected, but
>>>  ??? shortly after it's detection an FC relogin procedure is
>>> necessary e.g. due to
>>>  ??? an RSCN. In this case, an `fc_udev_device` uevent will be
>>> received on the
>>>  ??? first detection and handled by an `nvme connect-all` command
>>> run from
>>>  ??? `nvmf-connect at .service`. The connection attempt to the rport in
>>> question will
>>>  ??? fail with "no such device" because of the simultaneous FC
>>>  ??? relogin. `nvmf-connect at .service` may not terminate immediately,
>>> because it
>>>  ??? attempts to establish other connections listed in the Discovery
>>> Log page it
>>>  ??? retrieved. When the FC relogin eventually finishes, a new
>>> uevent will be
>>>  ??? received, and `nvmf-connect@` will be started again, but *this
>>> has no effect*
>>>  ??? if the previous `nvmf-connect@` service hasn't finished yet.
>>> This is the
>>>  ??? general semantics of systemd services, no easy workaround
>>> exists.? **nvme
>>>  ??? monitor** doesn't suffer from this problem. If it sees an
>>> uevent for a
>>>  ??? transport address for which a discovery is already running, it
>>> will queue the
>>>  ??? handling of this event up and restart the discovery after it's
>>> finished.
>>
>> While I understand the issue, this reason alone is an overkill for
>> doing
>> this.
> 
> I agree. But it's not easy to fix the issue otherwise. In the customer
> problem where we observed it, I worked around it by adding the udev
> seqnum to the "instance name" of the systemd service, thus allowing
> several "nvme connect-all" processes to run for the same transport
> address simultaneously. But I don't think that would scale well;
> the monitor can handle it more cleanly.

Still changing the entire thing for a corner case...

> 
>>>  ? * Resource consumption for handling uevents is lower. Instead of
>>> running an
>>>  ??? udev worker, executing the rules, executing `systemctl start`
>>> from the
>>>  ??? worker, starting a systemd service, and starting a separate
>>> **nvme-cli**
>>>  ??? instance, only a single `fork()` operation is necessary. Of
>>> course, on the
>>>  ??? back side, the monitor itself consumes resources while it's
>>> running and
>>>  ??? waiting for events. On my system with 8 persistent discovery
>>> controllers,
>>>  ??? its RSS is ~3MB. CPU consumption is zero as long as no events
>>> occur.
>>
>> What is the baseline with what we have today?
> 
> A meaningful comparsion is difficult and should be done when the
> monitor functionality is finalized. I made this statement only to
> provide a rough idea of the resource usage, not more.

You mention that the utilization is lower than what we do today, hence
my question is by how much?

>>>  ? * **nvme monitor** could be easily extended to handle events for
>>> non-FC
>>>  ??? transports.
>>
>> Which events?
> 
> Network discovery, mDNS or the like. I haven't digged into the details
> yet.

Yes, that is possible, would probably be easier to do this in a higher
level language but libavahi can also do this...

>>> I've tested `fc_udev_device` handling for NVMeoFC with an Ontap
>>> target, and
>>> AEN handling for RDMA using a Linux **nvmet** target.
>>>
>>> ### Implementation notes
>>>
>>> I've tried to change the exisiting **nvme-cli** code as little as
>>> possible
>>> while reusing the code from `fabrics.c`. The majority of changes in
>>> the
>>> existing code exports formerly static functions and variables, so
>>> that they
>>> are usable from the monitor code.
>>
>> General comment, can you please separate out fixes/cleanups that are
>> not
>> related to the goal of this patchset?
> 
> Which ones are you referring to? 09 and 19? While these are minor
> improvements to the existing code, I wouldn't say they qualify as fixes
> or cleanups. They aren't necessary without adding the monitor code.

Patches that are not directly related to the goal of this should
be splitted out to ease the review.

> But yes, I can post all changes to existing code separately.
> 
>>>  ? *? When "add" uevents for nvme controller devices are received,
>>> the
>>>  ???? controller is consistently not in `live` state yet, and
>>> attempting to read
>>>  ???? the `subsysnqn` sysfs attribute returns `(efault)`. While this
>>> should
>>>  ???? arguably be fixed in the kernel, it could be worked around in
>>> user space
>>>  ???? by using timers or polling the `state` sysfs attribute for
>>> changes.
>>
>> This is a bug, what in the code causes this? nothing in controller
>> state
>> should prevent from this sysfs read from executing correctly...
> 
> I think it can be fixed by making nvme_sysfs_show_subsysnqn() fall back
> to ctrl->opts->subsysnqn if ctrl->subsys is NULL.
> 
> I'll send a patch. Anyway, it'll take time until this is fixed
> everywhere.

Thanks.

> 
>>
>>>  ? * Parse and handle `discovery.conf` on startup.
>>
>> This is a must I think, where do you get the known transport
>> addresses
>> on startup today?
> 
> There's a systemd service that runs "nvme connect-all" once during
> boot. That exists today. I'm not sure if it should be integrated in the
> monitor, perhaps it's good to keep these separate. People who don't
> need the monitor can still run the existing service only, whereas for
> others, the two would play together just fine.

Then doesn't this service need to run after it?

>>>  ? * Implement support for RDMA and TCP protocols.
>>
>> What is needed for supporting them? Not sure I follow (I thought
>> you mentioned that you tested against linux nvmet-rdma?)
>>
> 
> AENs over existing discovery controllers are supported for all
> transports. But there's no support for discovery of new transports
> except for NVMeoFC's "fc_udev_device" mechanism.

I see. thanks.


From sagi at grimberg.me  Fri Jan 29 15:09:17 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Fri, 29 Jan 2021 12:09:17 -0800
Subject: [PATCH 11/35] monitor: add option -A / --autoconnect
In-Reply-To: <cbf4808b0becc3978b758d5be5cc3f3c1c6fe86f.camel@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-12-mwilck@suse.com>
 <d9c74675-a324-b863-1dee-454fc90d5e77@grimberg.me>
 <cbf4808b0becc3978b758d5be5cc3f3c1c6fe86f.camel@suse.com>
Message-ID: <e48f239d-0642-c07a-a442-6922070ab23a@grimberg.me>


>>> With this option, the monitor will try to connect to newly
>>> discovered
>>> controllers.
>>
>> Maybe I'm missing something here, but what does it do without
>> autoconnect?
>>
> 
> Basically it just runs "nvme discover". When events come in,
> it runs the discovery and prints the results, like "discover" would.
> 
> We can change that of course.

But its a daemon, seems not very useful, but ok..


From sagi at grimberg.me  Fri Jan 29 15:16:36 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Fri, 29 Jan 2021 12:16:36 -0800
Subject: [PATCH 35/35] monitor: add option --keep/-K
In-Reply-To: <12827c5f748bd2eff31450c47bbef1cfc7b73459.camel@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-36-mwilck@suse.com>
 <90145500-c2c5-023c-6d69-27db6ee600a7@grimberg.me>
 <12827c5f748bd2eff31450c47bbef1cfc7b73459.camel@suse.com>
Message-ID: <400d4f5e-a578-e89f-ae45-7ed15d089a8d@grimberg.me>


>>> With this option, "nvme monitor" will keep created discovery
>>> controllers
>>> running even after it exits. If running in the initrd, this is will
>>> be
>>> done automatically. That has the advantage that the new monitor
>>> instance
>>> that will be started automatically after switching root can simply
>>> take
>>> over the already created discovery controllers.
>>
>> Why not make it the default?
> 
> Well, we've had a lot of discussions about persistent discovery
> connections not being universally loved. So I thought I'd make cleaning
> up the default.

Heh... well, I didn't see thus far of any other good suggestion on how
to propagate discovery change log events reliably (I've seen some bad
ones). And we are assuming that hosts need to know about these
changes...

The default matters here. The spec tells us how to learn about
change log events so I would suggest we follow it.


From mwilck at suse.com  Fri Jan 29 15:27:43 2021
From: mwilck at suse.com (Martin Wilck)
Date: Fri, 29 Jan 2021 21:27:43 +0100
Subject: [PATCH 00/35] RFC: add "nvme monitor" subcommand
In-Reply-To: <d8e35845-31d3-a46d-b464-728d751d0b33@grimberg.me>
References: <20210126203324.23610-1-mwilck@suse.com>
 <60846bb5-c0df-ac23-260b-b53afd48f661@grimberg.me>
 <d8956cf973867ad7cc6c4d968682ec3db3054aa3.camel@suse.com>
 <d8e35845-31d3-a46d-b464-728d751d0b33@grimberg.me>
Message-ID: <26138a83eee9362b1769940f6da86387716ab2d8.camel@suse.com>

On Fri, 2021-01-29 at 12:08 -0800, Sagi Grimberg wrote:
> 
> > > > 
> > > > This method for discovery and autodetection has some advantages
> > > > over the
> > > > current udev-rule based approach:
> > > > 
> > > > ?? * By using the `--persistent` option, users can easily
> > > > control
> > > > whether
> > > > ???? persistent discovery controllers for discovered transport
> > > > addresses should
> > > > ???? be created and monitored for AEN events. **nvme monitor**
> > > > watches known
> > > > ???? transport addresses, creates discovery controllers as
> > > > required,
> > > > and re-uses
> > > > ???? existing ones if possible.
> > > 
> > > What does that mean?
> > 
> > In general, if the monitor detects a new host_traddr/traddr/trsvcid
> > tuple, it runs a discovery on it, and keeps the discovery
> > controller
> > open if?--persistent was given. On startup, it scans existing
> > controllers, and if it finds already existing discovery
> > controllers,
> > re-uses them. These will not be shut down when the monitor exits.
> 
> And if it doesn't run with --persistent it deletes them? even if
> these
> weren't created by it?

No, not those. That's what I wanted to express with "These will not be
shut down when the monitor exits."

It's not trivial to determine reliably which controller the monitor
created and which it didn't. The current code assumes that all
discovery controllers that didn't exist at startup were created by the
monitor. We can improve the intelligence of the tool in that area, of
course. Currently it makes this dumb assumption.

> 
> And, if none exist where does it get new discovery controller
> details?
> Today we use discovery.conf for that.

As I said, this can be done with a separate "nvme connect-all" call,
which could be run from an ExecStartPre or from a separate service.
Or we can integrate the functionality in the monitor. I don't have a
strong opinion either way. I can adapt to what you guys prefer.

> 
> > This allows users fine-grained control about what discovery
> > controllers
> > to operate persistently. Users who want all discovery controllers
> > to be
> > persistent just use --persistent. Others can set up those that they
> > want to have (manually or with a script), and not use --persistent.
> > 
> > The background is that hosts may not need every detected discovery
> > controller to be persistent. In multipath scenarios, you may see
> > more
> > discovery subsystems than anything else, and not everyone likes
> > that.
> > That's a generic issue and unrelated to the monitor, but running
> > the
> > monitor with --persistent creates discovery controllers that would
> > otherwise not be visible.
> > 
> > Hope this clarifies it.
> 
> Well, How do people expect to know if stuff change without a
> persistent
> discovery controller? Not sure if people may see more discovery
> controllers this is a real issue given what they are getting from it.

You're right. At this very early stage, I wanted to give users the
freedom of choice, and not force dozens of discovery controller
connections upon everyone. If there's consensus that the discovery
connections should always be created, fine with me. 


> > I agree. But it's not easy to fix the issue otherwise. In the
> > customer
> > problem where we observed it, I worked around it by adding the udev
> > seqnum to the "instance name" of the systemd service, thus allowing
> > several "nvme connect-all" processes to run for the same transport
> > address simultaneously. But I don't think that would scale well;
> > the monitor can handle it more cleanly.
> 
> Still changing the entire thing for a corner case...

It's just one puzzle piece.

> > > > ?? * Resource consumption for handling uevents is lower.
> > > > Instead of
> > > > running an
> > > > ???? udev worker, executing the rules, executing `systemctl
> > > > start`
> > > > from the
> > > > ???? worker, starting a systemd service, and starting a
> > > > separate
> > > > **nvme-cli**
> > > > ???? instance, only a single `fork()` operation is necessary.
> > > > Of
> > > > course, on the
> > > > ???? back side, the monitor itself consumes resources while
> > > > it's
> > > > running and
> > > > ???? waiting for events. On my system with 8 persistent
> > > > discovery
> > > > controllers,
> > > > ???? its RSS is ~3MB. CPU consumption is zero as long as no
> > > > events
> > > > occur.
> > > 
> > > What is the baseline with what we have today?
> > 
> > A meaningful comparsion is difficult and should be done when the
> > monitor functionality is finalized. I made this statement only to
> > provide a rough idea of the resource usage, not more.
> 
> You mention that the utilization is lower than what we do today,
> hence
> my question is by how much?

I'll try to figure it out and come up with something. Sorry for the
hand-waving assertion. I admint It was speculative for the most part.

> > > > ?? * **nvme monitor** could be easily extended to handle events
> > > > for
> > > > non-FC
> > > > ???? transports.
> > > 
> > > Which events?
> > 
> > Network discovery, mDNS or the like. I haven't digged into the
> > details
> > yet.
> 
> Yes, that is possible, would probably be easier to do this in a
> higher
> level language but libavahi can also do this...

Enzo Matsumiya has been working on it, and we've been discussing how to
integrate his functionality into the monitor.

> > > 
> > > > ?? * Parse and handle `discovery.conf` on startup.
> > > 
> > > This is a must I think, where do you get the known transport
> > > addresses
> > > on startup today?
> > 
> > There's a systemd service that runs "nvme connect-all" once during
> > boot. That exists today. I'm not sure if it should be integrated in
> > the
> > monitor, perhaps it's good to keep these separate. People who don't
> > need the monitor can still run the existing service only, whereas
> > for
> > others, the two would play together just fine.
> 
> Then doesn't this service need to run after it?

Not necessarily. It can handle controllers that are created by other
processes while it's running.

Thanks for your comments,
Martin





From mwilck at suse.com  Fri Jan 29 15:30:33 2021
From: mwilck at suse.com (Martin Wilck)
Date: Fri, 29 Jan 2021 21:30:33 +0100
Subject: [PATCH 35/35] monitor: add option --keep/-K
In-Reply-To: <400d4f5e-a578-e89f-ae45-7ed15d089a8d@grimberg.me>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-36-mwilck@suse.com>
 <90145500-c2c5-023c-6d69-27db6ee600a7@grimberg.me>
 <12827c5f748bd2eff31450c47bbef1cfc7b73459.camel@suse.com>
 <400d4f5e-a578-e89f-ae45-7ed15d089a8d@grimberg.me>
Message-ID: <b4b9a52011d17ef16cbc86d81ef3d19f7a517d93.camel@suse.com>

On Fri, 2021-01-29 at 12:16 -0800, Sagi Grimberg wrote:
> 
> > > > With this option, "nvme monitor" will keep created discovery
> > > > controllers
> > > > running even after it exits. If running in the initrd, this is
> > > > will
> > > > be
> > > > done automatically. That has the advantage that the new monitor
> > > > instance
> > > > that will be started automatically after switching root can
> > > > simply
> > > > take
> > > > over the already created discovery controllers.
> > > 
> > > Why not make it the default?
> > 
> > Well, we've had a lot of discussions about persistent discovery
> > connections not being universally loved. So I thought I'd make
> > cleaning
> > up the default.
> 
> Heh... well, I didn't see thus far of any other good suggestion on
> how
> to propagate discovery change log events reliably (I've seen some bad
> ones). And we are assuming that hosts need to know about these
> changes...
> 
> The default matters here. The spec tells us how to learn about
> change log events so I would suggest we follow it.
> 

No problem, I can change this.

But I'm not quite following you here, because this option is about
keeping controllers up after the monitor exits. Given that the monitor
would be the instance that receives the AENs and acts upon them, what's
the point of keeping them alive after it has terminated?

Martin






From sagi at grimberg.me  Fri Jan 29 15:45:03 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Fri, 29 Jan 2021 12:45:03 -0800
Subject: [PATCH 35/35] monitor: add option --keep/-K
In-Reply-To: <b4b9a52011d17ef16cbc86d81ef3d19f7a517d93.camel@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-36-mwilck@suse.com>
 <90145500-c2c5-023c-6d69-27db6ee600a7@grimberg.me>
 <12827c5f748bd2eff31450c47bbef1cfc7b73459.camel@suse.com>
 <400d4f5e-a578-e89f-ae45-7ed15d089a8d@grimberg.me>
 <b4b9a52011d17ef16cbc86d81ef3d19f7a517d93.camel@suse.com>
Message-ID: <c127bde8-7cae-677c-4b8d-44cf757d05eb@grimberg.me>


>>>>> With this option, "nvme monitor" will keep created discovery
>>>>> controllers
>>>>> running even after it exits. If running in the initrd, this is
>>>>> will
>>>>> be
>>>>> done automatically. That has the advantage that the new monitor
>>>>> instance
>>>>> that will be started automatically after switching root can
>>>>> simply
>>>>> take
>>>>> over the already created discovery controllers.
>>>>
>>>> Why not make it the default?
>>>
>>> Well, we've had a lot of discussions about persistent discovery
>>> connections not being universally loved. So I thought I'd make
>>> cleaning
>>> up the default.
>>
>> Heh... well, I didn't see thus far of any other good suggestion on
>> how
>> to propagate discovery change log events reliably (I've seen some bad
>> ones). And we are assuming that hosts need to know about these
>> changes...
>>
>> The default matters here. The spec tells us how to learn about
>> change log events so I would suggest we follow it.
>>
> 
> No problem, I can change this.
> 
> But I'm not quite following you here, because this option is about
> keeping controllers up after the monitor exits. Given that the monitor
> would be the instance that receives the AENs and acts upon them, what's
> the point of keeping them alive after it has terminated?

It may run again at some point.


From mwilck at suse.com  Fri Jan 29 15:51:04 2021
From: mwilck at suse.com (Martin Wilck)
Date: Fri, 29 Jan 2021 21:51:04 +0100
Subject: [PATCH 35/35] monitor: add option --keep/-K
In-Reply-To: <c127bde8-7cae-677c-4b8d-44cf757d05eb@grimberg.me>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-36-mwilck@suse.com>
 <90145500-c2c5-023c-6d69-27db6ee600a7@grimberg.me>
 <12827c5f748bd2eff31450c47bbef1cfc7b73459.camel@suse.com>
 <400d4f5e-a578-e89f-ae45-7ed15d089a8d@grimberg.me>
 <b4b9a52011d17ef16cbc86d81ef3d19f7a517d93.camel@suse.com>
 <c127bde8-7cae-677c-4b8d-44cf757d05eb@grimberg.me>
Message-ID: <2394e23e80f2bdcf0a95eb39e5eefcb00237d52f.camel@suse.com>

On Fri, 2021-01-29 at 12:45 -0800, Sagi Grimberg wrote:
> 
> > > > > 
> > 
> > But I'm not quite following you here, because this option is about
> > keeping controllers up after the monitor exits. Given that the
> > monitor
> > would be the instance that receives the AENs and acts upon them,
> > what's
> > the point of keeping them alive after it has terminated?
> 
> It may run again at some point.
> 

If it does, it will recreate discovery controllers for every
host_traddr/traddr/trsvcid tuple it finds. "--keep" semantics are only
necessary for addresses on which no regular (non-discovery) connection
exists.

Martin




From sagi at grimberg.me  Fri Jan 29 15:57:32 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Fri, 29 Jan 2021 12:57:32 -0800
Subject: [PATCH 35/35] monitor: add option --keep/-K
In-Reply-To: <2394e23e80f2bdcf0a95eb39e5eefcb00237d52f.camel@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-36-mwilck@suse.com>
 <90145500-c2c5-023c-6d69-27db6ee600a7@grimberg.me>
 <12827c5f748bd2eff31450c47bbef1cfc7b73459.camel@suse.com>
 <400d4f5e-a578-e89f-ae45-7ed15d089a8d@grimberg.me>
 <b4b9a52011d17ef16cbc86d81ef3d19f7a517d93.camel@suse.com>
 <c127bde8-7cae-677c-4b8d-44cf757d05eb@grimberg.me>
 <2394e23e80f2bdcf0a95eb39e5eefcb00237d52f.camel@suse.com>
Message-ID: <8cb1830e-b7f3-48ef-1190-0d917aa200bb@grimberg.me>


>>> But I'm not quite following you here, because this option is about
>>> keeping controllers up after the monitor exits. Given that the
>>> monitor
>>> would be the instance that receives the AENs and acts upon them,
>>> what's
>>> the point of keeping them alive after it has terminated?
>>
>> It may run again at some point.
>>
> 
> If it does, it will recreate discovery controllers for every
> host_traddr/traddr/trsvcid tuple it finds. "--keep" semantics are only
> necessary for addresses on which no regular (non-discovery) connection
> exists.

Wait, Maybe I'm missing something here, but are you saying that for
every traddr/trsvcid it finds (both nvm and discovery) it will attempt
to connect a discovery controller?

If so, this is absolutely wrong.


From mwilck at suse.com  Fri Jan 29 16:05:26 2021
From: mwilck at suse.com (Martin Wilck)
Date: Fri, 29 Jan 2021 22:05:26 +0100
Subject: [PATCH 35/35] monitor: add option --keep/-K
In-Reply-To: <8cb1830e-b7f3-48ef-1190-0d917aa200bb@grimberg.me>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-36-mwilck@suse.com>
 <90145500-c2c5-023c-6d69-27db6ee600a7@grimberg.me>
 <12827c5f748bd2eff31450c47bbef1cfc7b73459.camel@suse.com>
 <400d4f5e-a578-e89f-ae45-7ed15d089a8d@grimberg.me>
 <b4b9a52011d17ef16cbc86d81ef3d19f7a517d93.camel@suse.com>
 <c127bde8-7cae-677c-4b8d-44cf757d05eb@grimberg.me>
 <2394e23e80f2bdcf0a95eb39e5eefcb00237d52f.camel@suse.com>
 <8cb1830e-b7f3-48ef-1190-0d917aa200bb@grimberg.me>
Message-ID: <5623aeee6a57889123b8a3441ee6df7b97f76451.camel@suse.com>

On Fri, 2021-01-29 at 12:57 -0800, Sagi Grimberg wrote:
> 
> > > > But I'm not quite following you here, because this option is
> > > > about
> > > > keeping controllers up after the monitor exits. Given that the
> > > > monitor
> > > > would be the instance that receives the AENs and acts upon
> > > > them,
> > > > what's
> > > > the point of keeping them alive after it has terminated?
> > > 
> > > It may run again at some point.
> > > 
> > 
> > If it does, it will recreate discovery controllers for every
> > host_traddr/traddr/trsvcid tuple it finds. "--keep" semantics are
> > only
> > necessary for addresses on which no regular (non-discovery)
> > connection
> > exists.
> 
> Wait, Maybe I'm missing something here, but are you saying that for
> every traddr/trsvcid it finds (both nvm and discovery) it will
> attempt
> to connect a discovery controller?
> 
> If so, this is absolutely wrong.

Currently, it tries to do that on startup, if (and only if) the?
--startup option is given. My expectation was that the connection
attempts would simply fail if there was no discovery subsystem to
connect to. Anyway, it's not the default behavior, and can be dropped
completely if it's so bad that we shouldn't ever attempt to do it.

If the service is started early on during boot, and event-based
discovery works (i.e. we also have the mDNS part in place), this won't
be necessary of course.

Regards
Martin







From sagi at grimberg.me  Fri Jan 29 16:06:31 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Fri, 29 Jan 2021 13:06:31 -0800
Subject: [PATCH 26/35] monitor: implement starting discovery controllers
 on startup
In-Reply-To: <20210126203324.23610-27-mwilck@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-27-mwilck@suse.com>
Message-ID: <18970cbc-1c58-9529-3bb5-919249e97b5c@grimberg.me>


> If the -U/--startup option is used, nvme monitor looks for exsiting
> nvme controllers on startup, and runs a discovery on the associated
> transport address (connection); i.e. tries to connect to a discovery
> subsystem on the same address, retrieve the discovery log pages,
> and (if --autoconnect is given) connect all listed controllers.

Oh no no no no... This is a completely wrong assumption to make. Nothing
suggest that an nvme controller will have a discovery controller on the
same port.

There is a discovery controller and an NVM controller, the only
connection between the two is that a discovery controller can
refer to an nvme controller (or a different discovery controller).

Information about discovery controllers may be obtained in different
ways, but it absolutely cannot be obtained by any nvme controller.

Now I understand a bit more on the --keep discussion. The monitor
should today get discovery controller endpoints from a conf file
(maybe discovery.conf) and in the future by any other automatic
way, not even looking into the currently connected nvme controllers.


From sagi at grimberg.me  Fri Jan 29 16:11:59 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Fri, 29 Jan 2021 13:11:59 -0800
Subject: [PATCH 35/35] monitor: add option --keep/-K
In-Reply-To: <5623aeee6a57889123b8a3441ee6df7b97f76451.camel@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-36-mwilck@suse.com>
 <90145500-c2c5-023c-6d69-27db6ee600a7@grimberg.me>
 <12827c5f748bd2eff31450c47bbef1cfc7b73459.camel@suse.com>
 <400d4f5e-a578-e89f-ae45-7ed15d089a8d@grimberg.me>
 <b4b9a52011d17ef16cbc86d81ef3d19f7a517d93.camel@suse.com>
 <c127bde8-7cae-677c-4b8d-44cf757d05eb@grimberg.me>
 <2394e23e80f2bdcf0a95eb39e5eefcb00237d52f.camel@suse.com>
 <8cb1830e-b7f3-48ef-1190-0d917aa200bb@grimberg.me>
 <5623aeee6a57889123b8a3441ee6df7b97f76451.camel@suse.com>
Message-ID: <552cb65a-8f1b-e414-4de8-f53ff469e8a1@grimberg.me>


>>> If it does, it will recreate discovery controllers for every
>>> host_traddr/traddr/trsvcid tuple it finds. "--keep" semantics are
>>> only
>>> necessary for addresses on which no regular (non-discovery)
>>> connection
>>> exists.
>>
>> Wait, Maybe I'm missing something here, but are you saying that for
>> every traddr/trsvcid it finds (both nvm and discovery) it will
>> attempt
>> to connect a discovery controller?
>>
>> If so, this is absolutely wrong.
> 
> Currently, it tries to do that on startup, if (and only if) the
> --startup option is given. My expectation was that the connection
> attempts would simply fail if there was no discovery subsystem to
> connect to. Anyway, it's not the default behavior, and can be dropped
> completely if it's so bad that we shouldn't ever attempt to do it.

IMO it needs to be dropped. I didn't understand this at first because
it never even occurred to me that such an assumption can be even made.

> If the service is started early on during boot, and event-based
> discovery works (i.e. we also have the mDNS part in place), this won't
> be necessary of course.

This isn't necessary regardless. At best the discovery controller
endpoints should be obtained from discovery.conf or equivalent.

I don't even see how does this help in early boot anyways, how
do the existing controllers get connected?


From mwilck at suse.com  Fri Jan 29 16:13:00 2021
From: mwilck at suse.com (Martin Wilck)
Date: Fri, 29 Jan 2021 22:13:00 +0100
Subject: [PATCH 26/35] monitor: implement starting discovery controllers
 on startup
In-Reply-To: <18970cbc-1c58-9529-3bb5-919249e97b5c@grimberg.me>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-27-mwilck@suse.com>
 <18970cbc-1c58-9529-3bb5-919249e97b5c@grimberg.me>
Message-ID: <0c56ef14e84354f9601dbe694c7550d77d990f54.camel@suse.com>

On Fri, 2021-01-29 at 13:06 -0800, Sagi Grimberg wrote:
> 
> > If the -U/--startup option is used, nvme monitor looks for exsiting
> > nvme controllers on startup, and runs a discovery on the associated
> > transport address (connection); i.e. tries to connect to a
> > discovery
> > subsystem on the same address, retrieve the discovery log pages,
> > and (if --autoconnect is given) connect all listed controllers.
> 
> Oh no no no no... This is a completely wrong assumption to make.
> Nothing
> suggest that an nvme controller will have a discovery controller on
> the
> same port.
> 
> There is a discovery controller and an NVM controller, the only
> connection between the two is that a discovery controller can
> refer to an nvme controller (or a different discovery controller).
> 
> Information about discovery controllers may be obtained in different
> ways, but it absolutely cannot be obtained by any nvme controller.
> 
> Now I understand a bit more on the --keep discussion. The monitor
> should today get discovery controller endpoints from a conf file
> (maybe discovery.conf) and in the future by any other automatic
> way, not even looking into the currently connected nvme controllers.
> 

I hear you. I'll drop this in the next version, no problem.?

I didn't expect that probing for a discovery controller was a problem.
IIUC, if we get an fc_udev_device event for a NVMe remote port, we
can't be sure that that remote port offers a discovery controller,
either. We try to connect, and give up if it fails.

Martin




From mwilck at suse.com  Fri Jan 29 16:15:42 2021
From: mwilck at suse.com (Martin Wilck)
Date: Fri, 29 Jan 2021 22:15:42 +0100
Subject: [PATCH 35/35] monitor: add option --keep/-K
In-Reply-To: <552cb65a-8f1b-e414-4de8-f53ff469e8a1@grimberg.me>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-36-mwilck@suse.com>
 <90145500-c2c5-023c-6d69-27db6ee600a7@grimberg.me>
 <12827c5f748bd2eff31450c47bbef1cfc7b73459.camel@suse.com>
 <400d4f5e-a578-e89f-ae45-7ed15d089a8d@grimberg.me>
 <b4b9a52011d17ef16cbc86d81ef3d19f7a517d93.camel@suse.com>
 <c127bde8-7cae-677c-4b8d-44cf757d05eb@grimberg.me>
 <2394e23e80f2bdcf0a95eb39e5eefcb00237d52f.camel@suse.com>
 <8cb1830e-b7f3-48ef-1190-0d917aa200bb@grimberg.me>
 <5623aeee6a57889123b8a3441ee6df7b97f76451.camel@suse.com>
 <552cb65a-8f1b-e414-4de8-f53ff469e8a1@grimberg.me>
Message-ID: <c00de29ef02bf39ae231a2816f03c8e920ebdc29.camel@suse.com>

On Fri, 2021-01-29 at 13:11 -0800, Sagi Grimberg wrote:
> 
> > > > If it does, it will recreate discovery controllers for every
> > > > host_traddr/traddr/trsvcid tuple it finds. "--keep" semantics
> > > > are
> > > > only
> > > > necessary for addresses on which no regular (non-discovery)
> > > > connection
> > > > exists.
> > > 
> > > Wait, Maybe I'm missing something here, but are you saying that
> > > for
> > > every traddr/trsvcid it finds (both nvm and discovery) it will
> > > attempt
> > > to connect a discovery controller?
> > > 
> > > If so, this is absolutely wrong.
> > 
> > Currently, it tries to do that on startup, if (and only if) the
> > --startup option is given. My expectation was that the connection
> > attempts would simply fail if there was no discovery subsystem to
> > connect to. Anyway, it's not the default behavior, and can be
> > dropped
> > completely if it's so bad that we shouldn't ever attempt to do it.
> 
> IMO it needs to be dropped. I didn't understand this at first because
> it never even occurred to me that such an assumption can be even
> made.
> 
> > If the service is started early on during boot, and event-based
> > discovery works (i.e. we also have the mDNS part in place), this
> > won't
> > be necessary of course.
> 
> This isn't necessary regardless. At best the discovery controller
> endpoints should be obtained from discovery.conf or equivalent.

Understood.

> I don't even see how does this help in early boot anyways, how
> do the existing controllers get connected?

For FC, it works today. You can start the monitor in the initrd, it
will receive the fc_udev_device events, and autoconnect (just like
traditional udev/systemd based discovery). For other transports, it'd
be more work, as we'd need to do mDNS discovery from an initrd
environment. I wouldn't say it's impossible though.

Martin




From sagi at grimberg.me  Fri Jan 29 16:18:14 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Fri, 29 Jan 2021 13:18:14 -0800
Subject: [PATCH 26/35] monitor: implement starting discovery controllers
 on startup
In-Reply-To: <0c56ef14e84354f9601dbe694c7550d77d990f54.camel@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-27-mwilck@suse.com>
 <18970cbc-1c58-9529-3bb5-919249e97b5c@grimberg.me>
 <0c56ef14e84354f9601dbe694c7550d77d990f54.camel@suse.com>
Message-ID: <809c3240-50d9-cc86-9ae8-878c62e49460@grimberg.me>


>>> If the -U/--startup option is used, nvme monitor looks for exsiting
>>> nvme controllers on startup, and runs a discovery on the associated
>>> transport address (connection); i.e. tries to connect to a
>>> discovery
>>> subsystem on the same address, retrieve the discovery log pages,
>>> and (if --autoconnect is given) connect all listed controllers.
>>
>> Oh no no no no... This is a completely wrong assumption to make.
>> Nothing
>> suggest that an nvme controller will have a discovery controller on
>> the
>> same port.
>>
>> There is a discovery controller and an NVM controller, the only
>> connection between the two is that a discovery controller can
>> refer to an nvme controller (or a different discovery controller).
>>
>> Information about discovery controllers may be obtained in different
>> ways, but it absolutely cannot be obtained by any nvme controller.
>>
>> Now I understand a bit more on the --keep discussion. The monitor
>> should today get discovery controller endpoints from a conf file
>> (maybe discovery.conf) and in the future by any other automatic
>> way, not even looking into the currently connected nvme controllers.
>>
> 
> I hear you. I'll drop this in the next version, no problem.
> 
> I didn't expect that probing for a discovery controller was a problem.

It's not a "problem" in the sense that nothing devastating will happen.
it's just wrong. One can also randomize a transport endpoint and attempt
to connect to it.

> IIUC, if we get an fc_udev_device event for a NVMe remote port, we
> can't be sure that that remote port offers a discovery controller,
> either. We try to connect, and give up if it fails.

I'm assuming that this is what the spec mandates the host should do,
which is not the case here.


From sagi at grimberg.me  Fri Jan 29 16:21:22 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Fri, 29 Jan 2021 13:21:22 -0800
Subject: [PATCH 35/35] monitor: add option --keep/-K
In-Reply-To: <c00de29ef02bf39ae231a2816f03c8e920ebdc29.camel@suse.com>
References: <20210126203324.23610-1-mwilck@suse.com>
 <20210126203324.23610-36-mwilck@suse.com>
 <90145500-c2c5-023c-6d69-27db6ee600a7@grimberg.me>
 <12827c5f748bd2eff31450c47bbef1cfc7b73459.camel@suse.com>
 <400d4f5e-a578-e89f-ae45-7ed15d089a8d@grimberg.me>
 <b4b9a52011d17ef16cbc86d81ef3d19f7a517d93.camel@suse.com>
 <c127bde8-7cae-677c-4b8d-44cf757d05eb@grimberg.me>
 <2394e23e80f2bdcf0a95eb39e5eefcb00237d52f.camel@suse.com>
 <8cb1830e-b7f3-48ef-1190-0d917aa200bb@grimberg.me>
 <5623aeee6a57889123b8a3441ee6df7b97f76451.camel@suse.com>
 <552cb65a-8f1b-e414-4de8-f53ff469e8a1@grimberg.me>
 <c00de29ef02bf39ae231a2816f03c8e920ebdc29.camel@suse.com>
Message-ID: <01314926-1d33-53e1-165d-346290101ba7@grimberg.me>


>> I don't even see how does this help in early boot anyways, how
>> do the existing controllers get connected?
> 
> For FC, it works today. You can start the monitor in the initrd, it
> will receive the fc_udev_device events, and autoconnect (just like
> traditional udev/systemd based discovery). For other transports, it'd
> be more work, as we'd need to do mDNS discovery from an initrd
> environment. I wouldn't say it's impossible though.

I was referring to the nvme controller walk and connect a discovery
controller to that endpoint. I thought you meant that this helps
you at early boot time.


From sagi at grimberg.me  Fri Jan 29 17:10:21 2021
From: sagi at grimberg.me (Sagi Grimberg)
Date: Fri, 29 Jan 2021 14:10:21 -0800
Subject: [PATCH] nvme-tcp: proper handling of tcp socket closing flows
In-Reply-To: <20210128152758.114112-1-elad.grupi@dell.com>
References: <20210128152758.114112-1-elad.grupi@dell.com>
Message-ID: <a3c4ef7f-45df-c071-8e00-074d1e48eaca@grimberg.me>


> @@ -1453,9 +1453,27 @@ static int nvmet_tcp_set_queue_sock(struct nvmet_tcp_queue *queue)
>   	sock->sk->sk_state_change = nvmet_tcp_state_change;
>   	queue->write_space = sock->sk->sk_write_space;
>   	sock->sk->sk_write_space = nvmet_tcp_write_space;
> +
> +	switch (sk->sk_state) {
> +	case TCP_FIN_WAIT1:
> +	case TCP_CLOSE_WAIT:
> +	case TCP_CLOSE:

BTW, shouldn't this be if (sk->sk_state != TCP_ESTABLISHED) ?


From borispismenny at gmail.com  Sun Jan 31 02:51:12 2021
From: borispismenny at gmail.com (Boris Pismenny)
Date: Sun, 31 Jan 2021 09:51:12 +0200
Subject: [PATCH v2 net-next 06/21] nvme-tcp: Add DDP offload control path
In-Reply-To: <37861060-9651-49c8-e583-2b070914361c@gmail.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
 <20210114151033.13020-7-borisp@mellanox.com>
 <37861060-9651-49c8-e583-2b070914361c@gmail.com>
Message-ID: <c9d06a90-4e7d-b5aa-eabb-63b557b8b5d0@gmail.com>

On 19/01/2021 5:47, David Ahern wrote:
> On 1/14/21 8:10 AM, Boris Pismenny wrote:
>> +static
>> +int nvme_tcp_offload_socket(struct nvme_tcp_queue *queue)
>> +{
>> +	struct net_device *netdev = get_netdev_for_sock(queue->sock->sk, true);
>> +	struct nvme_tcp_ddp_config config = {};
>> +	int ret;
>> +
>> +	if (!netdev) {
>> +		dev_info_ratelimited(queue->ctrl->ctrl.device, "netdev not found\n");
>> +		return -ENODEV;
>> +	}
>> +
>> +	if (!(netdev->features & NETIF_F_HW_TCP_DDP)) {
>> +		dev_put(netdev);
>> +		return -EOPNOTSUPP;
>> +	}
>> +
>> +	config.cfg.type		= TCP_DDP_NVME;
>> +	config.pfv		= NVME_TCP_PFV_1_0;
>> +	config.cpda		= 0;
>> +	config.dgst		= queue->hdr_digest ?
>> +		NVME_TCP_HDR_DIGEST_ENABLE : 0;
>> +	config.dgst		|= queue->data_digest ?
>> +		NVME_TCP_DATA_DIGEST_ENABLE : 0;
>> +	config.queue_size	= queue->queue_size;
>> +	config.queue_id		= nvme_tcp_queue_id(queue);
>> +	config.io_cpu		= queue->io_cpu;
>> +
>> +	ret = netdev->tcp_ddp_ops->tcp_ddp_sk_add(netdev,
>> +						  queue->sock->sk,
>> +						  (struct tcp_ddp_config *)&config);
> 
> typecast is not needed; tcp_ddp_config is an element of nvme_tcp_ddp_config
> 

True, will fix, thanks!

>> +	if (ret) {
>> +		dev_put(netdev);
>> +		return ret;
>> +	}
>> +
>> +	inet_csk(queue->sock->sk)->icsk_ulp_ddp_ops = &nvme_tcp_ddp_ulp_ops;
>> +	if (netdev->features & NETIF_F_HW_TCP_DDP)
>> +		set_bit(NVME_TCP_Q_OFF_DDP, &queue->flags);
>> +
>> +	return ret;
>> +}
>> +
>> +static
>> +void nvme_tcp_unoffload_socket(struct nvme_tcp_queue *queue)
>> +{
>> +	struct net_device *netdev = queue->ctrl->offloading_netdev;
>> +
>> +	if (!netdev) {
>> +		dev_info_ratelimited(queue->ctrl->ctrl.device, "netdev not found\n");
>> +		return;
>> +	}
>> +
>> +	netdev->tcp_ddp_ops->tcp_ddp_sk_del(netdev, queue->sock->sk);
>> +
>> +	inet_csk(queue->sock->sk)->icsk_ulp_ddp_ops = NULL;
>> +	dev_put(netdev); /* put the queue_init get_netdev_for_sock() */
> 
> have you validated the netdev reference counts? You have a put here, and ...
> 

Yes, it does work for the cases we've tested: up/down,
connect/disconnect, and up/down during traffic. It is
unfortunate that it is not trivial to follow.
We'll add some comment to make it more clear. Also see
below.

>> +}
>> +
>> +static
>> +int nvme_tcp_offload_limits(struct nvme_tcp_queue *queue)
>> +{
>> +	struct net_device *netdev = get_netdev_for_sock(queue->sock->sk, true);
> 
> ... a get here ....
> 
>> +	struct tcp_ddp_limits limits;
>> +	int ret = 0;
>> +
>> +	if (!netdev) {
>> +		dev_info_ratelimited(queue->ctrl->ctrl.device, "netdev not found\n");
>> +		return -ENODEV;
>> +	}
>> +
>> +	if (netdev->features & NETIF_F_HW_TCP_DDP &&
>> +	    netdev->tcp_ddp_ops &&
>> +	    netdev->tcp_ddp_ops->tcp_ddp_limits)
>> +		ret = netdev->tcp_ddp_ops->tcp_ddp_limits(netdev, &limits);
>> +	else
>> +		ret = -EOPNOTSUPP;
>> +
>> +	if (!ret) {
>> +		queue->ctrl->offloading_netdev = netdev;
> 
> 
> ... you have the device here, but then ...
> 
>> +		dev_dbg_ratelimited(queue->ctrl->ctrl.device,
>> +				    "netdev %s offload limits: max_ddp_sgl_len %d\n",
>> +				    netdev->name, limits.max_ddp_sgl_len);
>> +		queue->ctrl->ctrl.max_segments = limits.max_ddp_sgl_len;
>> +		queue->ctrl->ctrl.max_hw_sectors =
>> +			limits.max_ddp_sgl_len << (ilog2(SZ_4K) - 9);
>> +	} else {
>> +		queue->ctrl->offloading_netdev = NULL;
>> +	}
>> +
>> +	dev_put(netdev);
> 
> ... put here. And this is the limit checking function which seems like
> an odd place to set offloading_netdev vs nvme_tcp_offload_socket which
> sets no queue variable but yet hangs on to a netdev reference count.
> 
> netdev reference count leaks are an absolute PITA to find. Code that
> takes and puts the counts should be clear and obvious as to when and
> why. The symmetry of offload and unoffload are clear when the offload
> saves the address in offloading_netdev. What you have now is dubious.
> 

The idea here is to rely on offload and unoffload to hold the netdev
during offload. Get limits is not offloading anything; it only queries
device limits that are then applied to the queue by the caller.
We hold the device here for only to ensure that the function is still
there when it is called, and we release it once we are done with it,
as no context is established on the NIC, and no offload takes place.


From borispismenny at gmail.com  Sun Jan 31 03:44:12 2021
From: borispismenny at gmail.com (Boris Pismenny)
Date: Sun, 31 Jan 2021 10:44:12 +0200
Subject: [PATCH v2 net-next 07/21] nvme-tcp: Add DDP data-path
In-Reply-To: <84cc2af1-22e8-abf5-07da-bc7b4a2b6b12@gmail.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
 <20210114151033.13020-8-borisp@mellanox.com>
 <84cc2af1-22e8-abf5-07da-bc7b4a2b6b12@gmail.com>
Message-ID: <419231da-615c-10c5-7c98-7e049ac54ee7@gmail.com>



On 19/01/2021 6:18, David Ahern wrote:
> On 1/14/21 8:10 AM, Boris Pismenny wrote:
>> @@ -664,8 +753,15 @@ static int nvme_tcp_process_nvme_cqe(struct nvme_tcp_queue *queue,
>>  		return -EINVAL;
>>  	}
>>  
>> -	if (!nvme_try_complete_req(rq, cqe->status, cqe->result))
>> -		nvme_complete_rq(rq);
>> +	req = blk_mq_rq_to_pdu(rq);
>> +	if (req->offloaded) {
>> +		req->status = cqe->status;
>> +		req->result = cqe->result;
>> +		nvme_tcp_teardown_ddp(queue, cqe->command_id, rq);
>> +	} else {
>> +		if (!nvme_try_complete_req(rq, cqe->status, cqe->result))
>> +			nvme_complete_rq(rq);
>> +	}
>>  	queue->nr_cqe++;
>>  
>>  	return 0;
>> @@ -859,9 +955,18 @@ static int nvme_tcp_recv_pdu(struct nvme_tcp_queue *queue, struct sk_buff *skb,
>>  static inline void nvme_tcp_end_request(struct request *rq, u16 status)
>>  {
>>  	union nvme_result res = {};
>> +	struct nvme_tcp_request *req = blk_mq_rq_to_pdu(rq);
>> +	struct nvme_tcp_queue *queue = req->queue;
>> +	struct nvme_tcp_data_pdu *pdu = (void *)queue->pdu;
>>  
>> -	if (!nvme_try_complete_req(rq, cpu_to_le16(status << 1), res))
>> -		nvme_complete_rq(rq);
>> +	if (req->offloaded) {
>> +		req->status = cpu_to_le16(status << 1);
>> +		req->result = res;
>> +		nvme_tcp_teardown_ddp(queue, pdu->command_id, rq);
>> +	} else {
>> +		if (!nvme_try_complete_req(rq, cpu_to_le16(status << 1), res))
>> +			nvme_complete_rq(rq);
>> +	}
>>  }
>>  
>>  static int nvme_tcp_recv_data(struct nvme_tcp_queue *queue, struct sk_buff *skb,
> 
> 
> The req->offload checks assume the offload is to the expected
> offload_netdev, but you do not verify the data arrived as expected. You
> might get lucky if both netdev's belong to the same PCI device (assuming
> the h/w handles it a certain way), but it will not if the netdev's
> belong to different devices.
> 
> Consider a system with 2 network cards -- even if it is 2 mlx5 based
> devices. One setup can have the system using a bond with 1 port from
> each PCI device. The tx path picks a leg based on the hash of the ntuple
> and that (with Tariq's bond patches) becomes the expected offload
> device. A similar example holds for a pure routing setup with ECMP. For
> both there is full redundancy in the network - separate NIC cards
> connected to separate TORs to have independent network paths.
> 
> A packet arrives on the *other* netdevice - you have *no* control over
> the Rx path. Your current checks will think the packet arrived with DDP
> but it did not.
> 

There's no problem if another (non-offload) netdevice receives traffic
that arrives here. Because that other device will never set the SKB
frag pages to point to the final destination buffers, and so copy
offload will not take place.

The req->offload indication is mainly for matching ddp_setup with
ddp_teardown calls, it does not control copy/crc offload as these are
controlled per-skb using frags for copy and skb bits for crc.



From borispismenny at gmail.com  Sun Jan 31 04:27:31 2021
From: borispismenny at gmail.com (Boris Pismenny)
Date: Sun, 31 Jan 2021 11:27:31 +0200
Subject: [PATCH v2 net-next 19/21] net/mlx5e: NVMEoTCP, data-path for DDP
 offload
In-Reply-To: <2a0bfce0-6226-7b9a-95b1-15f4f1f321e8@gmail.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
 <20210114151033.13020-20-borisp@mellanox.com>
 <10c28b01-49e5-c512-8670-bf8332b24b1b@gmail.com>
 <15248743-82bf-4283-d8c6-99f2210e42ae@gmail.com>
 <2a0bfce0-6226-7b9a-95b1-15f4f1f321e8@gmail.com>
Message-ID: <f376794c-568b-9b87-7467-dfe433053a4d@gmail.com>

On 19/01/2021 6:36, David Ahern wrote:
> On 1/17/21 1:42 AM, Boris Pismenny wrote:
>> This is needed for a few reasons that are explained in detail
>> in the tcp-ddp offload documentation. See patch 21 overview
>> and rx-data-path sections. Our reasons are as follows:
> 
> I read the documentation patch, and it does not explain it and really
> should not since this is very mlx specific based on the changes.
> Different h/w will have different limitations. Given that, it would be
> best to enhance the patch description to explain why these gymnastics
> are needed for the skb.
> 

The text in the documentation that describes this trade-off:
''We remark that a single TCP packet may have numerous PDUs embedded
inside. NICs can choose to offload one or more of these PDUs according
to various trade-offs. Possibly, offloading such small PDUs is of little
value, and it is better to leave it to software. ``

Indeed, different HW may have other additional trade-offs. But, I
suspect that this one will be important for all.

>> 1) Each SKB may contain multiple PDUs. DDP offload doesn't operate on
>> PDU headers, so these are written in the receive ring. Therefore, we
>> need to rebuild the SKB to account for it. Additionally, due to HW
>> limitations, we will only offload the first PDU in the SKB.
> 
> Are you referring to LRO skbs here? I can't imagine going through this
> for 1500 byte packets that have multiple PDUs.
> 
> 

No, that is true for any skb, and non-LRO skbs in particular. Most SKBs
do not contain multiple PDUs, but the ones that do are handled
gracefully in this function.




From borispismenny at gmail.com  Sun Jan 31 05:40:09 2021
From: borispismenny at gmail.com (Boris Pismenny)
Date: Sun, 31 Jan 2021 12:40:09 +0200
Subject: [PATCH v2 net-next 02/21] net: Introduce direct data placement
 tcp offload
In-Reply-To: <CANn89i+7HNP6o5TkR9WKW3QkuH0cCArETfGTis8PWPR64BTFEQ@mail.gmail.com>
References: <20210114151033.13020-1-borisp@mellanox.com>
 <20210114151033.13020-3-borisp@mellanox.com>
 <CANn89iJaFRFxVe-eV7hcwC_5Zp+HtWHxTQt+BNYcKOwZUriSDg@mail.gmail.com>
 <62d4606a-0a41-2b12-cf16-3523d0b73573@gmail.com>
 <CANn89i+7HNP6o5TkR9WKW3QkuH0cCArETfGTis8PWPR64BTFEQ@mail.gmail.com>
Message-ID: <8e4cd169-f1b7-0f39-eaad-8cf441077f84@gmail.com>



On 14/01/2021 22:43, Eric Dumazet wrote:
> On Thu, Jan 14, 2021 at 9:19 PM Boris Pismenny <borispismenny at gmail.com> wrote:
>>
>>
>>
>> On 14/01/2021 17:57, Eric Dumazet wrote:
>>> On Thu, Jan 14, 2021 at 4:10 PM Boris Pismenny <borisp at mellanox.com> wrote:
>>>>
>>>> This commit introduces direct data placement offload for TCP.
>>>> This capability is accompanied by new net_device operations that
>>>> configure hardware contexts. There is a context per socket, and a context per DDP
>>>> opreation. Additionally, a resynchronization routine is used to assist
>>>> hardware handle TCP OOO, and continue the offload.
>>>> Furthermore, we let the offloading driver advertise what is the max hw
>>>> sectors/segments.
>>>>
>>>> Using this interface, the NIC hardware will scatter TCP payload directly
>>>> to the BIO pages according to the command_id.
>>>> To maintain the correctness of the network stack, the driver is expected
>>>> to construct SKBs that point to the BIO pages.
>>>>
>>>> This, the SKB represents the data on the wire, while it is pointing
>>>> to data that is already placed in the destination buffer.
>>>> As a result, data from page frags should not be copied out to
>>>> the linear part.
>>>>
>>>> As SKBs that use DDP are already very memory efficient, we modify
>>>> skb_condence to avoid copying data from fragments to the linear
>>>> part of SKBs that belong to a socket that uses DDP offload.
>>>>
>>>> A follow-up patch will use this interface for DDP in NVMe-TCP.
>>>>
>>>> Signed-off-by: Boris Pismenny <borisp at mellanox.com>
>>>> Signed-off-by: Ben Ben-Ishay <benishay at mellanox.com>
>>>> Signed-off-by: Or Gerlitz <ogerlitz at mellanox.com>
>>>> Signed-off-by: Yoray Zack <yorayz at mellanox.com>
>>>> ---
>>>>  include/linux/netdev_features.h    |   2 +
>>>>  include/linux/netdevice.h          |   5 ++
>>>>  include/net/inet_connection_sock.h |   4 +
>>>>  include/net/tcp_ddp.h              | 136 +++++++++++++++++++++++++++++
>>>>  net/Kconfig                        |   9 ++
>>>>  net/core/skbuff.c                  |   9 +-
>>>>  net/ethtool/common.c               |   1 +
>>>>  7 files changed, 165 insertions(+), 1 deletion(-)
>>>>  create mode 100644 include/net/tcp_ddp.h
>>>>
>>>> diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h
>>>> index 934de56644e7..fb35dcac03d2 100644
>>>> --- a/include/linux/netdev_features.h
>>>> +++ b/include/linux/netdev_features.h
>>>> @@ -84,6 +84,7 @@ enum {
>>>>         NETIF_F_GRO_FRAGLIST_BIT,       /* Fraglist GRO */
>>>>
>>>>         NETIF_F_HW_MACSEC_BIT,          /* Offload MACsec operations */
>>>> +       NETIF_F_HW_TCP_DDP_BIT,         /* TCP direct data placement offload */
>>>>
>>>>         /*
>>>>          * Add your fresh new feature above and remember to update
>>>> @@ -157,6 +158,7 @@ enum {
>>>>  #define NETIF_F_GRO_FRAGLIST   __NETIF_F(GRO_FRAGLIST)
>>>>  #define NETIF_F_GSO_FRAGLIST   __NETIF_F(GSO_FRAGLIST)
>>>>  #define NETIF_F_HW_MACSEC      __NETIF_F(HW_MACSEC)
>>>> +#define NETIF_F_HW_TCP_DDP     __NETIF_F(HW_TCP_DDP)
>>>>
>>>>  /* Finds the next feature with the highest number of the range of start till 0.
>>>>   */
>>>> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
>>>> index 259be67644e3..3dd3cdf5dec3 100644
>>>> --- a/include/linux/netdevice.h
>>>> +++ b/include/linux/netdevice.h
>>>> @@ -941,6 +941,7 @@ struct dev_ifalias {
>>>>
>>>>  struct devlink;
>>>>  struct tlsdev_ops;
>>>> +struct tcp_ddp_dev_ops;
>>>>
>>>>  struct netdev_name_node {
>>>>         struct hlist_node hlist;
>>>> @@ -1937,6 +1938,10 @@ struct net_device {
>>>>         const struct tlsdev_ops *tlsdev_ops;
>>>>  #endif
>>>>
>>>> +#ifdef CONFIG_TCP_DDP
>>>> +       const struct tcp_ddp_dev_ops *tcp_ddp_ops;
>>>> +#endif
>>>> +
>>>>         const struct header_ops *header_ops;
>>>>
>>>>         unsigned int            flags;
>>>> diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h
>>>> index 7338b3865a2a..a08b85b53aa8 100644
>>>> --- a/include/net/inet_connection_sock.h
>>>> +++ b/include/net/inet_connection_sock.h
>>>> @@ -66,6 +66,8 @@ struct inet_connection_sock_af_ops {
>>>>   * @icsk_ulp_ops          Pluggable ULP control hook
>>>>   * @icsk_ulp_data         ULP private data
>>>>   * @icsk_clean_acked      Clean acked data hook
>>>> + * @icsk_ulp_ddp_ops      Pluggable ULP direct data placement control hook
>>>> + * @icsk_ulp_ddp_data     ULP direct data placement private data
>>>>   * @icsk_listen_portaddr_node  hash to the portaddr listener hashtable
>>>>   * @icsk_ca_state:        Congestion control state
>>>>   * @icsk_retransmits:     Number of unrecovered [RTO] timeouts
>>>> @@ -94,6 +96,8 @@ struct inet_connection_sock {
>>>>         const struct tcp_ulp_ops  *icsk_ulp_ops;
>>>>         void __rcu                *icsk_ulp_data;
>>>>         void (*icsk_clean_acked)(struct sock *sk, u32 acked_seq);
>>>
>>> #ifdef CONFIG_TCP_DDP ?
>>>
>>>> +       const struct tcp_ddp_ulp_ops  *icsk_ulp_ddp_ops;
>>>> +       void __rcu                *icsk_ulp_ddp_data;
>>>>         struct hlist_node         icsk_listen_portaddr_node;
>>>>         unsigned int              (*icsk_sync_mss)(struct sock *sk, u32 pmtu);
>>>>         __u8                      icsk_ca_state:5,
>>>> diff --git a/include/net/tcp_ddp.h b/include/net/tcp_ddp.h
>>>> new file mode 100644
>>>> index 000000000000..31e5b1a16d0f
>>>> --- /dev/null
>>>> +++ b/include/net/tcp_ddp.h
>>>> @@ -0,0 +1,136 @@
>>>> +/* SPDX-License-Identifier: GPL-2.0
>>>> + *
>>>> + * tcp_ddp.h
>>>> + *     Author: Boris Pismenny <borisp at mellanox.com>
>>>> + *     Copyright (C) 2021 Mellanox Technologies.
>>>> + */
>>>> +#ifndef _TCP_DDP_H
>>>> +#define _TCP_DDP_H
>>>> +
>>>> +#include <linux/netdevice.h>
>>>> +#include <net/inet_connection_sock.h>
>>>> +#include <net/sock.h>
>>>> +
>>>> +/* limits returned by the offload driver, zero means don't care */
>>>> +struct tcp_ddp_limits {
>>>> +       int      max_ddp_sgl_len;
>>>> +};
>>>> +
>>>> +enum tcp_ddp_type {
>>>> +       TCP_DDP_NVME = 1,
>>>> +};
>>>> +
>>>> +/**
>>>> + * struct tcp_ddp_config - Generic tcp ddp configuration: tcp ddp IO queue
>>>> + * config implementations must use this as the first member.
>>>> + * Add new instances of tcp_ddp_config below (nvme-tcp, etc.).
>>>> + */
>>>> +struct tcp_ddp_config {
>>>> +       enum tcp_ddp_type    type;
>>>> +       unsigned char        buf[];
>>>> +};
>>>> +
>>>> +/**
>>>> + * struct nvme_tcp_ddp_config - nvme tcp ddp configuration for an IO queue
>>>> + *
>>>> + * @pfv:        pdu version (e.g., NVME_TCP_PFV_1_0)
>>>> + * @cpda:       controller pdu data alignmend (dwords, 0's based)
>>>> + * @dgst:       digest types enabled.
>>>> + *              The netdev will offload crc if ddp_crc is supported.
>>>> + * @queue_size: number of nvme-tcp IO queue elements
>>>> + * @queue_id:   queue identifier
>>>> + * @cpu_io:     cpu core running the IO thread for this queue
>>>> + */
>>>> +struct nvme_tcp_ddp_config {
>>>> +       struct tcp_ddp_config   cfg;
>>>> +
>>>> +       u16                     pfv;
>>>> +       u8                      cpda;
>>>> +       u8                      dgst;
>>>> +       int                     queue_size;
>>>> +       int                     queue_id;
>>>> +       int                     io_cpu;
>>>> +};
>>>> +
>>>> +/**
>>>> + * struct tcp_ddp_io - tcp ddp configuration for an IO request.
>>>> + *
>>>> + * @command_id:  identifier on the wire associated with these buffers
>>>> + * @nents:       number of entries in the sg_table
>>>> + * @sg_table:    describing the buffers for this IO request
>>>> + * @first_sgl:   first SGL in sg_table
>>>> + */
>>>> +struct tcp_ddp_io {
>>>> +       u32                     command_id;
>>>> +       int                     nents;
>>>> +       struct sg_table         sg_table;
>>>> +       struct scatterlist      first_sgl[SG_CHUNK_SIZE];
>>>> +};
>>>> +
>>>> +/* struct tcp_ddp_dev_ops - operations used by an upper layer protocol to configure ddp offload
>>>> + *
>>>> + * @tcp_ddp_limits:    limit the number of scatter gather entries per IO.
>>>> + *                     the device driver can use this to limit the resources allocated per queue.
>>>> + * @tcp_ddp_sk_add:    add offload for the queue represennted by the socket+config pair.
>>>> + *                     this function is used to configure either copy, crc or both offloads.
>>>> + * @tcp_ddp_sk_del:    remove offload from the socket, and release any device related resources.
>>>> + * @tcp_ddp_setup:     request copy offload for buffers associated with a command_id in tcp_ddp_io.
>>>> + * @tcp_ddp_teardown:  release offload resources association between buffers and command_id in
>>>> + *                     tcp_ddp_io.
>>>> + * @tcp_ddp_resync:    respond to the driver's resync_request. Called only if resync is successful.
>>>> + */
>>>> +struct tcp_ddp_dev_ops {
>>>> +       int (*tcp_ddp_limits)(struct net_device *netdev,
>>>> +                             struct tcp_ddp_limits *limits);
>>>> +       int (*tcp_ddp_sk_add)(struct net_device *netdev,
>>>> +                             struct sock *sk,
>>>> +                             struct tcp_ddp_config *config);
>>>> +       void (*tcp_ddp_sk_del)(struct net_device *netdev,
>>>> +                              struct sock *sk);
>>>> +       int (*tcp_ddp_setup)(struct net_device *netdev,
>>>> +                            struct sock *sk,
>>>> +                            struct tcp_ddp_io *io);
>>>> +       int (*tcp_ddp_teardown)(struct net_device *netdev,
>>>> +                               struct sock *sk,
>>>> +                               struct tcp_ddp_io *io,
>>>> +                               void *ddp_ctx);
>>>> +       void (*tcp_ddp_resync)(struct net_device *netdev,
>>>> +                              struct sock *sk, u32 seq);
>>>> +};
>>>> +
>>>> +#define TCP_DDP_RESYNC_REQ BIT(0)
>>>> +
>>>> +/**
>>>> + * struct tcp_ddp_ulp_ops - Interface to register uppper layer Direct Data Placement (DDP) TCP offload
>>>> + */
>>>> +struct tcp_ddp_ulp_ops {
>>>> +       /* NIC requests ulp to indicate if @seq is the start of a message */
>>>> +       bool (*resync_request)(struct sock *sk, u32 seq, u32 flags);
>>>> +       /* NIC driver informs the ulp that ddp teardown is done - used for async completions*/
>>>> +       void (*ddp_teardown_done)(void *ddp_ctx);
>>>> +};
>>>> +
>>>> +/**
>>>> + * struct tcp_ddp_ctx - Generic tcp ddp context: device driver per queue contexts must
>>>> + * use this as the first member.
>>>> + */
>>>> +struct tcp_ddp_ctx {
>>>> +       enum tcp_ddp_type    type;
>>>> +       unsigned char        buf[];
>>>> +};
>>>> +
>>>> +static inline struct tcp_ddp_ctx *tcp_ddp_get_ctx(const struct sock *sk)
>>>> +{
>>>> +       struct inet_connection_sock *icsk = inet_csk(sk);
>>>> +
>>>> +       return (__force struct tcp_ddp_ctx *)icsk->icsk_ulp_ddp_data;
>>>> +}
>>>> +
>>>> +static inline void tcp_ddp_set_ctx(struct sock *sk, void *ctx)
>>>> +{
>>>> +       struct inet_connection_sock *icsk = inet_csk(sk);
>>>> +
>>>> +       rcu_assign_pointer(icsk->icsk_ulp_ddp_data, ctx);
>>>> +}
>>>> +
>>>> +#endif //_TCP_DDP_H
>>>> diff --git a/net/Kconfig b/net/Kconfig
>>>> index f4c32d982af6..3876861cdc90 100644
>>>> --- a/net/Kconfig
>>>> +++ b/net/Kconfig
>>>> @@ -457,6 +457,15 @@ config ETHTOOL_NETLINK
>>>>           netlink. It provides better extensibility and some new features,
>>>>           e.g. notification messages.
>>>>
>>>> +config TCP_DDP
>>>> +       bool "TCP direct data placement offload"
>>>> +       default n
>>>> +       help
>>>> +         Direct Data Placement (DDP) offload for TCP enables ULP, such as
>>>> +         NVMe-TCP/iSCSI, to request the NIC to place TCP payload data
>>>> +         of a command response directly into kernel pages.
>>>> +
>>>> +
>>>>  endif   # if NET
>>>>
>>>>  # Used by archs to tell that they support BPF JIT compiler plus which flavour.
>>>> diff --git a/net/core/skbuff.c b/net/core/skbuff.c
>>>> index f62cae3f75d8..791c1b6bc067 100644
>>>> --- a/net/core/skbuff.c
>>>> +++ b/net/core/skbuff.c
>>>> @@ -69,6 +69,7 @@
>>>>  #include <net/xfrm.h>
>>>>  #include <net/mpls.h>
>>>>  #include <net/mptcp.h>
>>>> +#include <net/tcp_ddp.h>
>>>>
>>>>  #include <linux/uaccess.h>
>>>>  #include <trace/events/skb.h>
>>>> @@ -6140,9 +6141,15 @@ EXPORT_SYMBOL(pskb_extract);
>>>>   */
>>>>  void skb_condense(struct sk_buff *skb)
>>>>  {
>>>> +       bool is_ddp = false;
>>>> +
>>>> +#ifdef CONFIG_TCP_DDP
>>>
>>> This looks strange to me : TCP should call this helper while skb->sk is NULL
>>>
>>> Are you sure this is not dead code ?
>>>
>>
>> Will verify again on Sunday. AFAICT, early demux sets skb->sk before this code
>> is called.
> 
> 
> First, early demux is optional.
> 
> Secondly, skb->sk is stolen in skb_steal_sock() if early demux was performed.
> 
> 
> Just to clarify, the purpose of this code is to avoid skb condensing
>> data that is already placed into destination buffers.
> 
> Then this has not been tested. This suggests this code could be
> removed, I doubt that your target traffic would ever be 'condensed'.
> 

Thanks for the feedback!

Some retrospective about this:
We originally used the skb->ddp_crc bit for this check, but later we
tried to avoid it so as to reduce our dependence on said skb bit.
Unfortunately, that later change wasn't tested thoroughly.

We'll post v3 patches that will use the skb->ddp_crc bit for this check.
After re-testing with the new v3 patch I'm confident it will work.

>>
>>>> +       is_ddp = skb->sk && inet_csk(skb->sk) &&
>>>> +                inet_csk(skb->sk)->icsk_ulp_ddp_data;
>>>> +#endif
>>>>         if (skb->data_len) {
>>>>                 if (skb->data_len > skb->end - skb->tail ||
>>>> -                   skb_cloned(skb))
>>>> +                   skb_cloned(skb) || is_ddp)
>>>>                         return;
>>>>
>>>>                 /* Nice, we can free page frag(s) right now */
>>>> diff --git a/net/ethtool/common.c b/net/ethtool/common.c
>>>> index 24036e3055a1..a2ff7a4a6bbf 100644
>>>> --- a/net/ethtool/common.c
>>>> +++ b/net/ethtool/common.c
>>>> @@ -68,6 +68,7 @@ const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] = {
>>>>         [NETIF_F_HW_TLS_RX_BIT] =        "tls-hw-rx-offload",
>>>>         [NETIF_F_GRO_FRAGLIST_BIT] =     "rx-gro-list",
>>>>         [NETIF_F_HW_MACSEC_BIT] =        "macsec-hw-offload",
>>>> +       [NETIF_F_HW_TCP_DDP_BIT] =       "tcp-ddp-offload",
>>>>  };
>>>>
>>>>  const char
>>>> --
>>>> 2.24.1
>>>>


From Elad.Grupi at dell.com  Sun Jan 31 10:47:07 2021
From: Elad.Grupi at dell.com (Grupi, Elad)
Date: Sun, 31 Jan 2021 15:47:07 +0000
Subject: [PATCH] nvme-tcp: proper handling of tcp socket closing flows
In-Reply-To: <9d974783-dc05-61b1-902e-a0cbe13199f0@grimberg.me>
References: <20210128152758.114112-1-elad.grupi@dell.com>
 <2c2a3aa6-ca43-e9b0-7928-28c6962ea1bc@grimberg.me>
 <DM6PR19MB40113530FCB4DF6F52E8C752EFBA9@DM6PR19MB4011.namprd19.prod.outlook.com>
 <9d974783-dc05-61b1-902e-a0cbe13199f0@grimberg.me>
Message-ID: <DM6PR19MB4011E46B215215B04910F67CEFB79@DM6PR19MB4011.namprd19.prod.outlook.com>

Is it possible that we will have the following flow:

Thread 1 taking sk_callback_lock and goes into the switch case of sk_state, going to line:
	sock->sk->sk_user_data = queue;

at that point, thread 2 invokes sk_state_change, but this is still the original state_change callback because we didn't set yet to nvmet_tcp_state_change.

Thread 1 continues and set the callback to nvmet_tcp_state_change, but the state was already changed and nvmet_tcp_state_change will be never called.

I think this race still exist even when locked by sk_callback_lock.


-----Original Message-----
From: Sagi Grimberg <sagi at grimberg.me> 
Sent: Friday, 29 January 2021 1:34
To: Grupi, Elad; linux-nvme at lists.infradead.org
Subject: Re: [PATCH] nvme-tcp: proper handling of tcp socket closing flows


[EXTERNAL EMAIL] 


> That will work if sk_state_change is called under sk_callback_lock.

It is.

> In addition, need to flush_work(&queue->port->accept_work) in nvmet_tcp_release_queue_work because accept_work is still using queue struct after unlocking sk_callback_lock.


But sk->sk_user_data was not set, so I don't see how the release work can invoke.

> What about this instead?
> --
> diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c 
> index c41902f7ce39..6388d18ca7c2 100644
> --- a/drivers/nvme/target/tcp.c
> +++ b/drivers/nvme/target/tcp.c
> @@ -1494,16 +1494,28 @@ static int nvmet_tcp_set_queue_sock(struct nvmet_tcp_queue *queue)
>                   ip_sock_set_tos(sock->sk, inet->rcv_tos);
> 
>           write_lock_bh(&sock->sk->sk_callback_lock);
> -       sock->sk->sk_user_data = queue;
> -       queue->data_ready = sock->sk->sk_data_ready;
> -       sock->sk->sk_data_ready = nvmet_tcp_data_ready;
> -       queue->state_change = sock->sk->sk_state_change;
> -       sock->sk->sk_state_change = nvmet_tcp_state_change;
> -       queue->write_space = sock->sk->sk_write_space;
> -       sock->sk->sk_write_space = nvmet_tcp_write_space;
> +       switch (sk->sk_state) {
> +       case TCP_FIN_WAIT1:
> +       case TCP_CLOSE_WAIT:
> +       case TCP_CLOSE:
> +               /*
> +                * If the socket is already closing, don't even start
> +                * consuming it
> +                */
> +               ret = -ENOTCONN;
> +               break;
> +       default:
> +               sock->sk->sk_user_data = queue;
> +               queue->data_ready = sock->sk->sk_data_ready;
> +               sock->sk->sk_data_ready = nvmet_tcp_data_ready;
> +               queue->state_change = sock->sk->sk_state_change;
> +               sock->sk->sk_state_change = nvmet_tcp_state_change;
> +               queue->write_space = sock->sk->sk_write_space;
> +               sock->sk->sk_write_space = nvmet_tcp_write_space;
> +       }
>           write_unlock_bh(&sock->sk->sk_callback_lock);
> 
> -       return 0;
> +       return ret;
>    }
> --
> 

From Elad.Grupi at dell.com  Sun Jan 31 10:47:22 2021
From: Elad.Grupi at dell.com (Grupi, Elad)
Date: Sun, 31 Jan 2021 15:47:22 +0000
Subject: [PATCH] nvme-tcp: proper handling of tcp socket closing flows
In-Reply-To: <a3c4ef7f-45df-c071-8e00-074d1e48eaca@grimberg.me>
References: <20210128152758.114112-1-elad.grupi@dell.com>
 <a3c4ef7f-45df-c071-8e00-074d1e48eaca@grimberg.me>
Message-ID: <DM6PR19MB40115B3CE827B63255F0C2EEEFB79@DM6PR19MB4011.namprd19.prod.outlook.com>

Yes. That's looks good

-----Original Message-----
From: Sagi Grimberg <sagi at grimberg.me> 
Sent: Saturday, 30 January 2021 0:10
To: Grupi, Elad; linux-nvme at lists.infradead.org
Subject: Re: [PATCH] nvme-tcp: proper handling of tcp socket closing flows


[EXTERNAL EMAIL] 


> @@ -1453,9 +1453,27 @@ static int nvmet_tcp_set_queue_sock(struct nvmet_tcp_queue *queue)
>   	sock->sk->sk_state_change = nvmet_tcp_state_change;
>   	queue->write_space = sock->sk->sk_write_space;
>   	sock->sk->sk_write_space = nvmet_tcp_write_space;
> +
> +	switch (sk->sk_state) {
> +	case TCP_FIN_WAIT1:
> +	case TCP_CLOSE_WAIT:
> +	case TCP_CLOSE:

BTW, shouldn't this be if (sk->sk_state != TCP_ESTABLISHED) ?

From Elad.Grupi at dell.com  Sun Jan 31 10:48:38 2021
From: Elad.Grupi at dell.com (Grupi, Elad)
Date: Sun, 31 Jan 2021 15:48:38 +0000
Subject: [PATCH] nvme-tcp: fix a segmentation fault during io parsing error
In-Reply-To: <DM6PR19MB4011D61F1BF2A4F66228E9EEEFA50@DM6PR19MB4011.namprd19.prod.outlook.com>
References: <20210113115152.69692-1-elad.grupi@dell.com>
 <ad9f038b-9920-21da-755c-85f4e2228a22@grimberg.me>
 <DM6PR19MB401194016A086DDF8A82C554EFA80@DM6PR19MB4011.namprd19.prod.outlook.com>
 <f5b8dbc2-7960-894e-47ea-b18665536e70@grimberg.me>
 <DM6PR19MB4011A4116FAB37BEC28BBC91EFA80@DM6PR19MB4011.namprd19.prod.outlook.com>
 <6459e22f-f2f2-9183-0862-654bcc5e90eb@grimberg.me>
 <DM6PR19MB4011D61F1BF2A4F66228E9EEEFA50@DM6PR19MB4011.namprd19.prod.outlook.com>
Message-ID: <DM6PR19MB401175FEE24AD30B1289DA3EEFB79@DM6PR19MB4011.namprd19.prod.outlook.com>

Any update about this issue?

-----Original Message-----
From: Grupi, Elad 
Sent: Sunday, 17 January 2021 11:47
To: Sagi Grimberg; linux-nvme at lists.infradead.org
Subject: RE: [PATCH] nvme-tcp: fix a segmentation fault during io parsing error

Yes, it was reproduced with the validity check of resv1 field of connect command.

Jan 17 09:43:36 FNM00183301763-A kernel: nvmet_tcp: failed cmd 000000006fe9c801 id 0 opcode 127, data_len: 1024                                                                                                                                          
Jan 17 09:43:36 FNM00183301763-A kernel: general protection fault: 0000 [#1] SMP NOPTI                                                                                                                                                                   
Jan 17 09:43:36 FNM00183301763-A kernel: CPU: 10 PID: 615 Comm: kworker/10:1H Kdump: loaded Tainted: P           OE     4.19.158-coreos-r9999.188fe4a1ba192d57eaaa3462db70e1d9 #1                                                                        
Jan 17 09:43:36 FNM00183301763-A kernel: Hardware name: EMC 900-532-002/110-551-910C-01, BIOS 20.12 11/12/2020                                                                                                                                           
Jan 17 09:43:36 FNM00183301763-A kernel: Workqueue: nvmet_tcp_wq nvmet_tcp_io_work [nvmet_tcp]                                                                                                                                                           
Jan 17 09:43:36 FNM00183301763-A kernel: RIP: 0010:memcpy_erms+0x6/0x10                                                                                                                                                                                  
Jan 17 09:43:36 FNM00183301763-A kernel: Code: 90 90 90 90 eb 1e 0f 1f 00 48 89 f8 48 89 d1 48 c1 e9 03 83 e2 07 f3 48 a5 89 d1 f3 a4 c3 66 0f 1f 44 00 00 48 89 f8 48 89 d1 <f3> a4 c3 0f 1f 80 00 00 00 00 48 89 f8 48 83 fa 20 72 7e 40 38 fe         
Jan 17 09:43:36 FNM00183301763-A kernel: RSP: 0018:ffffc90007bc3c70 EFLAGS: 00010206 Jan 17 09:43:36 FNM00183301763-A kernel: RAX: 34e40d75735a3225 RBX: 0000000000000400 RCX: 0000000000000400 Jan 17 09:43:36 FNM00183301763-A kernel: RDX: 0000000000000400 RSI: ffff8887f03368ca RDI: 34e40d75735a3225 Jan 17 09:43:36 FNM00183301763-A kernel: RBP: ffff88884ead9d60 R08: ffff8888b53e0530 R09: ffff889789776b4c Jan 17 09:43:36 FNM00183301763-A kernel: R10: ffff8897897766c8 R11: ffff8887f03368ca R12: 0000000000000400 Jan 17 09:43:36 FNM00183301763-A kernel: R13: 0000000000000400 R14: ffff8887f0336cca R15: 0000000000000000 Jan 17 09:43:36 FNM00183301763-A kernel: FS:  0000000000000000(0000) GS:ffff8897dfe80000(0000) knlGS:0000000000000000 Jan 17 09:43:36 FNM00183301763-A kernel: CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033 Jan 17 09:43:36 FNM00183301763-A kernel: CR2: 00007f592924d890 CR3: 000000000220a002 CR4: 00000000007606e0 Jan 17 09:43:36 FNM00183301763-A kernel: DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 Jan 17 09:43:36 FNM00183301763-A kernel: DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Jan 17 09:43:36 FNM00183301763-A kernel: PKRU: 55555554 Jan 17 09:43:36 FNM00183301763-A kernel: Call Trace:
Jan 17 09:43:36 FNM00183301763-A kernel:  _copy_to_iter+0x333/0x3d0 Jan 17 09:43:36 FNM00183301763-A kernel:  ? tcp_write_xmit+0x403/0xfe0 Jan 17 09:43:36 FNM00183301763-A kernel:  skb_copy_datagram_iter+0x7b/0x260 Jan 17 09:43:36 FNM00183301763-A kernel:  tcp_recvmsg+0x238/0xc90 Jan 17 09:43:36 FNM00183301763-A kernel:  ? tcp_sendpage_locked+0x44/0x60 Jan 17 09:43:36 FNM00183301763-A kernel:  ? __local_bh_enable_ip+0x60/0x70 Jan 17 09:43:36 FNM00183301763-A kernel:  ? tcp_sendpage+0x41/0x50 Jan 17 09:43:36 FNM00183301763-A kernel:  inet_recvmsg+0x5b/0xd0 Jan 17 09:43:36 FNM00183301763-A kernel:  nvmet_tcp_io_work+0x116/0xb40 [nvmet_tcp] Jan 17 09:43:36 FNM00183301763-A kernel:  process_one_work+0x206/0x400 Jan 17 09:43:36 FNM00183301763-A kernel:  worker_thread+0x2d/0x3e0 Jan 17 09:43:36 FNM00183301763-A kernel:  ? process_one_work+0x400/0x400 Jan 17 09:43:36 FNM00183301763-A kernel:  kthread+0x112/0x130 Jan 17 09:43:36 FNM00183301763-A kernel:  ? kthread_bind+0x20/0x20 Jan 17 09:43:36 FNM00183301763-A kernel:  ret_from_fork+0x1f/0x40


-----Original Message-----
From: Sagi Grimberg <sagi at grimberg.me>
Sent: Saturday, 16 January 2021 3:19
To: Grupi, Elad; linux-nvme at lists.infradead.org
Subject: Re: [PATCH] nvme-tcp: fix a segmentation fault during io parsing error


[EXTERNAL EMAIL] 


>> This was a silly typo, did you check if it addressed your issue when you applied the needed change?
> 
> Yes. We applied the needed change before testing your patch, but still had kernel panic on recv flow when we had unread inline data on the socket.


Can you share the stack trace?

From lengchao at huawei.com  Sun Jan 31 21:16:35 2021
From: lengchao at huawei.com (Chao Leng)
Date: Mon, 1 Feb 2021 10:16:35 +0800
Subject: [PATCH v2] nvme-multipath: Early exit if no path is available
In-Reply-To: <ac019690-7f02-d28c-ed58-bfc8c1d48879@suse.de>
References: <20210127103033.15318-1-dwagner@suse.de>
 <db9baae0-547c-7ff4-8b2c-0b95f14be67c@huawei.com>
 <20210128075837.u5u56t23fq5gu6ou@beryllium.lan>
 <69575290-200e-b4a1-4269-c71e4c2cc37b@huawei.com>
 <20210128094004.erwnszjqcxlsi2kd@beryllium.lan>
 <ebb1d098-3ded-e592-4419-e905aabe824f@huawei.com>
 <675d3cf7-1ae8-adc5-b6d0-359fe10f6b23@grimberg.me>
 <59cd053e-46cb-0235-141f-4ce919c93f48@huawei.com>
 <65392653-6b03-9195-f686-5fe4b3290bd2@suse.de>
 <81b22bbf-4dd3-6161-e63a-9699690a4e4f@huawei.com>
 <715dd943-0587-be08-2840-e0948cf0bc62@suse.de>
 <eb131d8f-f009-42e7-105d-58b84060f0dd@huawei.com>
 <ac019690-7f02-d28c-ed58-bfc8c1d48879@suse.de>
Message-ID: <6ceff3cb-c9e9-7e74-92f0-dd745987c943@huawei.com>



On 2021/1/29 17:20, Hannes Reinecke wrote:
> On 1/29/21 9:46 AM, Chao Leng wrote:
>>
>>
>> On 2021/1/29 16:33, Hannes Reinecke wrote:
>>> On 1/29/21 8:45 AM, Chao Leng wrote:
>>>>
>>>>
>>>> On 2021/1/29 15:06, Hannes Reinecke wrote:
>>>>> On 1/29/21 4:07 AM, Chao Leng wrote:
>>>>>>
>>>>>>
>>>>>> On 2021/1/29 9:42, Sagi Grimberg wrote:
>>>>>>>
>>>>>>>>> You can't see exactly where it dies but I followed the assembly to
>>>>>>>>> nvme_round_robin_path(). Maybe it's not the initial nvme_next_ns(head,
>>>>>>>>> old) which returns NULL but nvme_next_ns() is returning NULL eventually
>>>>>>>>> (list_next_or_null_rcu()).
>>>>>>>> So there is other bug cause nvme_next_ns abormal.
>>>>>>>> I review the code about head->list and head->current_path, I find 2 bugs
>>>>>>>> may cause the bug:
>>>>>>>> First, I already send the patch. see:
>>>>>>>> https://lore.kernel.org/linux-nvme/20210128033351.22116-1-lengchao at huawei.com/
>>>>>>>> Second, in nvme_ns_remove, list_del_rcu is before
>>>>>>>> nvme_mpath_clear_current_path. This may cause "old" is deleted from the
>>>>>>>> "head", but still use "old". I'm not sure there's any other
>>>>>>>> consideration here, I will check it and try to fix it.
>>>>>>>
>>>>>>> The reason why we first remove from head->list and only then clear
>>>>>>> current_path is because the other way around there is no way
>>>>>>> to guarantee that that the ns won't be assigned as current_path
>>>>>>> again (because it is in head->list).
>>>>>> ok, I see.
>>>>>>>
>>>>>>> nvme_ns_remove fences continue of deletion of the ns by synchronizing
>>>>>>> the srcu such that for sure the current_path clearance is visible.
>>>>>> The list will be like this:
>>>>>> head->next = ns1;
>>>>>> ns1->next = head;
>>>>>> old->next = ns1;
>>>>>
>>>>> Where does 'old' pointing to?
>>>>>
>>>>>> This may cause infinite loop in nvme_round_robin_path.
>>>>>> for (ns = nvme_next_ns(head, old);
>>>>>> ?????ns != old;
>>>>>> ?????ns = nvme_next_ns(head, ns))
>>>>>> The ns will always be ns1, and then infinite loop.
>>>>>
>>>>> No. nvme_next_ns() will return NULL.
>>>> If there is just one path(the "old") and the "old" is deleted,
>>>> nvme_next_ns() will return NULL.
>>>> The list like this:
>>>> head->next = head;
>>>> old->next = head;
>>>> If there is two or more path and the "old" is deleted,
>>>> "for" will be infinite loop. because nvme_next_ns() will return
>>>> the path which in the list except the "old", check condition will
>>>> be true for ever.
>>>
>>> But that will be caught by the statement above:
>>>
>>> if (list_is_singular(&head->list))
>>>
>>> no?
>> Two path just a sample example.
>> If there is just two path, will enter it, may cause no path but there is
>> actually one path. It is falsely assumed that the "old" must be not deleted.
>> If there is more than two path, will cause infinite loop.
> So you mean we'll need something like this?
> 
> diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
> index 71696819c228..8ffccaf9c19a 100644
> --- a/drivers/nvme/host/multipath.c
> +++ b/drivers/nvme/host/multipath.c
> @@ -202,10 +202,12 @@ static struct nvme_ns *__nvme_find_path(struct nvme_ns_head *head, int node)
>  ?static struct nvme_ns *nvme_next_ns(struct nvme_ns_head *head,
>  ??????????????? struct nvme_ns *ns)
>  ?{
> -?????? ns = list_next_or_null_rcu(&head->list, &ns->siblings, struct nvme_ns,
> -?????????????????????? siblings);
> -?????? if (ns)
> -?????????????? return ns;
> +?????? if (ns) {
> +?????????????? ns = list_next_or_null_rcu(&head->list, &ns->siblings,
> +????????????????????????????????????????? struct nvme_ns, siblings);
> +?????????????? if (ns)
> +?????????????????????? return ns;
> +?????? }
No, in the scenario, ns should not be NULL.
May be we can do like this:

diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
index 282b7a4ea9a9..b895011a2cbd 100644
--- a/drivers/nvme/host/multipath.c
+++ b/drivers/nvme/host/multipath.c
@@ -199,30 +199,24 @@ static struct nvme_ns *__nvme_find_path(struct nvme_ns_head *head, int node)
         return found;
  }

-static struct nvme_ns *nvme_next_ns(struct nvme_ns_head *head,
-               struct nvme_ns *ns)
-{
-       ns = list_next_or_null_rcu(&head->list, &ns->siblings, struct nvme_ns,
-                       siblings);
-       if (ns)
-               return ns;
-       return list_first_or_null_rcu(&head->list, struct nvme_ns, siblings);
-}
+#define nvme_next_ns_condition(head, current, condition) \
+({ \
+       struct nvme_ns *__ptr = list_next_or_null_rcu(&(head)->list, \
+               &(current)->siblings, struct nvme_ns, siblings); \
+       __ptr ? __ptr : (condition) ? (condition) = false, \
+               list_first_or_null_rcu(&(head)->list, struct nvme_ns, \
+                       siblings) : NULL; \
+})

  static struct nvme_ns *nvme_round_robin_path(struct nvme_ns_head *head,
                 int node, struct nvme_ns *old)
  {
         struct nvme_ns *ns, *found = NULL;
+       bool first_half = true;

-       if (list_is_singular(&head->list)) {
-               if (nvme_path_is_disabled(old))
-                       return NULL;
-               return old;
-       }
-
-       for (ns = nvme_next_ns(head, old);
+       for (ns = nvme_next_ns_condition(head, old, first_half);
              ns && ns != old;
-            ns = nvme_next_ns(head, ns)) {
+            ns = nvme_next_ns_condition(head, ns, first_half)) {
                 if (nvme_path_is_disabled(ns))
                         continue;

>  ??????? return list_first_or_null_rcu(&head->list, struct nvme_ns, siblings);
>  ?}
> 
> Cheers,
> 
> Hannes


From lengchao at huawei.com  Sun Jan 31 21:16:35 2021
From: lengchao at huawei.com (Chao Leng)
Date: Mon, 1 Feb 2021 10:16:35 +0800
Subject: [PATCH v2] nvme-multipath: Early exit if no path is available
In-Reply-To: <ac019690-7f02-d28c-ed58-bfc8c1d48879@suse.de>
References: <20210127103033.15318-1-dwagner@suse.de>
 <db9baae0-547c-7ff4-8b2c-0b95f14be67c@huawei.com>
 <20210128075837.u5u56t23fq5gu6ou@beryllium.lan>
 <69575290-200e-b4a1-4269-c71e4c2cc37b@huawei.com>
 <20210128094004.erwnszjqcxlsi2kd@beryllium.lan>
 <ebb1d098-3ded-e592-4419-e905aabe824f@huawei.com>
 <675d3cf7-1ae8-adc5-b6d0-359fe10f6b23@grimberg.me>
 <59cd053e-46cb-0235-141f-4ce919c93f48@huawei.com>
 <65392653-6b03-9195-f686-5fe4b3290bd2@suse.de>
 <81b22bbf-4dd3-6161-e63a-9699690a4e4f@huawei.com>
 <715dd943-0587-be08-2840-e0948cf0bc62@suse.de>
 <eb131d8f-f009-42e7-105d-58b84060f0dd@huawei.com>
 <ac019690-7f02-d28c-ed58-bfc8c1d48879@suse.de>
Message-ID: <6ceff3cb-c9e9-7e74-92f0-dd745987c943@huawei.com>



On 2021/1/29 17:20, Hannes Reinecke wrote:
> On 1/29/21 9:46 AM, Chao Leng wrote:
>>
>>
>> On 2021/1/29 16:33, Hannes Reinecke wrote:
>>> On 1/29/21 8:45 AM, Chao Leng wrote:
>>>>
>>>>
>>>> On 2021/1/29 15:06, Hannes Reinecke wrote:
>>>>> On 1/29/21 4:07 AM, Chao Leng wrote:
>>>>>>
>>>>>>
>>>>>> On 2021/1/29 9:42, Sagi Grimberg wrote:
>>>>>>>
>>>>>>>>> You can't see exactly where it dies but I followed the assembly to
>>>>>>>>> nvme_round_robin_path(). Maybe it's not the initial nvme_next_ns(head,
>>>>>>>>> old) which returns NULL but nvme_next_ns() is returning NULL eventually
>>>>>>>>> (list_next_or_null_rcu()).
>>>>>>>> So there is other bug cause nvme_next_ns abormal.
>>>>>>>> I review the code about head->list and head->current_path, I find 2 bugs
>>>>>>>> may cause the bug:
>>>>>>>> First, I already send the patch. see:
>>>>>>>> https://lore.kernel.org/linux-nvme/20210128033351.22116-1-lengchao at huawei.com/
>>>>>>>> Second, in nvme_ns_remove, list_del_rcu is before
>>>>>>>> nvme_mpath_clear_current_path. This may cause "old" is deleted from the
>>>>>>>> "head", but still use "old". I'm not sure there's any other
>>>>>>>> consideration here, I will check it and try to fix it.
>>>>>>>
>>>>>>> The reason why we first remove from head->list and only then clear
>>>>>>> current_path is because the other way around there is no way
>>>>>>> to guarantee that that the ns won't be assigned as current_path
>>>>>>> again (because it is in head->list).
>>>>>> ok, I see.
>>>>>>>
>>>>>>> nvme_ns_remove fences continue of deletion of the ns by synchronizing
>>>>>>> the srcu such that for sure the current_path clearance is visible.
>>>>>> The list will be like this:
>>>>>> head->next = ns1;
>>>>>> ns1->next = head;
>>>>>> old->next = ns1;
>>>>>
>>>>> Where does 'old' pointing to?
>>>>>
>>>>>> This may cause infinite loop in nvme_round_robin_path.
>>>>>> for (ns = nvme_next_ns(head, old);
>>>>>> ?????ns != old;
>>>>>> ?????ns = nvme_next_ns(head, ns))
>>>>>> The ns will always be ns1, and then infinite loop.
>>>>>
>>>>> No. nvme_next_ns() will return NULL.
>>>> If there is just one path(the "old") and the "old" is deleted,
>>>> nvme_next_ns() will return NULL.
>>>> The list like this:
>>>> head->next = head;
>>>> old->next = head;
>>>> If there is two or more path and the "old" is deleted,
>>>> "for" will be infinite loop. because nvme_next_ns() will return
>>>> the path which in the list except the "old", check condition will
>>>> be true for ever.
>>>
>>> But that will be caught by the statement above:
>>>
>>> if (list_is_singular(&head->list))
>>>
>>> no?
>> Two path just a sample example.
>> If there is just two path, will enter it, may cause no path but there is
>> actually one path. It is falsely assumed that the "old" must be not deleted.
>> If there is more than two path, will cause infinite loop.
> So you mean we'll need something like this?
> 
> diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
> index 71696819c228..8ffccaf9c19a 100644
> --- a/drivers/nvme/host/multipath.c
> +++ b/drivers/nvme/host/multipath.c
> @@ -202,10 +202,12 @@ static struct nvme_ns *__nvme_find_path(struct nvme_ns_head *head, int node)
>  ?static struct nvme_ns *nvme_next_ns(struct nvme_ns_head *head,
>  ??????????????? struct nvme_ns *ns)
>  ?{
> -?????? ns = list_next_or_null_rcu(&head->list, &ns->siblings, struct nvme_ns,
> -?????????????????????? siblings);
> -?????? if (ns)
> -?????????????? return ns;
> +?????? if (ns) {
> +?????????????? ns = list_next_or_null_rcu(&head->list, &ns->siblings,
> +????????????????????????????????????????? struct nvme_ns, siblings);
> +?????????????? if (ns)
> +?????????????????????? return ns;
> +?????? }
No, in the scenario, ns should not be NULL.
May be we can do like this:

diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
index 282b7a4ea9a9..b895011a2cbd 100644
--- a/drivers/nvme/host/multipath.c
+++ b/drivers/nvme/host/multipath.c
@@ -199,30 +199,24 @@ static struct nvme_ns *__nvme_find_path(struct nvme_ns_head *head, int node)
         return found;
  }

-static struct nvme_ns *nvme_next_ns(struct nvme_ns_head *head,
-               struct nvme_ns *ns)
-{
-       ns = list_next_or_null_rcu(&head->list, &ns->siblings, struct nvme_ns,
-                       siblings);
-       if (ns)
-               return ns;
-       return list_first_or_null_rcu(&head->list, struct nvme_ns, siblings);
-}
+#define nvme_next_ns_condition(head, current, condition) \
+({ \
+       struct nvme_ns *__ptr = list_next_or_null_rcu(&(head)->list, \
+               &(current)->siblings, struct nvme_ns, siblings); \
+       __ptr ? __ptr : (condition) ? (condition) = false, \
+               list_first_or_null_rcu(&(head)->list, struct nvme_ns, \
+                       siblings) : NULL; \
+})

  static struct nvme_ns *nvme_round_robin_path(struct nvme_ns_head *head,
                 int node, struct nvme_ns *old)
  {
         struct nvme_ns *ns, *found = NULL;
+       bool first_half = true;

-       if (list_is_singular(&head->list)) {
-               if (nvme_path_is_disabled(old))
-                       return NULL;
-               return old;
-       }
-
-       for (ns = nvme_next_ns(head, old);
+       for (ns = nvme_next_ns_condition(head, old, first_half);
              ns && ns != old;
-            ns = nvme_next_ns(head, ns)) {
+            ns = nvme_next_ns_condition(head, ns, first_half)) {
                 if (nvme_path_is_disabled(ns))
                         continue;

>  ??????? return list_first_or_null_rcu(&head->list, struct nvme_ns, siblings);
>  ?}
> 
> Cheers,
> 
> Hannes


From lengchao at huawei.com  Sun Jan 31 22:49:38 2021
From: lengchao at huawei.com (Chao Leng)
Date: Mon, 1 Feb 2021 11:49:38 +0800
Subject: [PATCH v5 1/3] blk-mq: introduce blk_mq_set_request_complete
In-Reply-To: <20210201034940.18891-1-lengchao@huawei.com>
References: <20210201034940.18891-1-lengchao@huawei.com>
Message-ID: <20210201034940.18891-2-lengchao@huawei.com>

nvme drivers need to set the state of request to MQ_RQ_COMPLETE when
directly complete request in queue_rq.
So add blk_mq_set_request_complete.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 include/linux/blk-mq.h | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h
index 47b021952ac7..38c632ce2270 100644
--- a/include/linux/blk-mq.h
+++ b/include/linux/blk-mq.h
@@ -494,6 +494,15 @@ static inline int blk_mq_request_completed(struct request *rq)
 	return blk_mq_rq_state(rq) == MQ_RQ_COMPLETE;
 }
 
+/*
+ * If nvme complete request directly, need to set the state to complete
+ * to avoid canceling the request again.
+ */
+static inline void blk_mq_set_request_complete(struct request *rq)
+{
+	WRITE_ONCE(rq->state, MQ_RQ_COMPLETE);
+}
+
 void blk_mq_start_request(struct request *rq);
 void blk_mq_end_request(struct request *rq, blk_status_t error);
 void __blk_mq_end_request(struct request *rq, blk_status_t error);
-- 
2.16.4



From lengchao at huawei.com  Sun Jan 31 22:49:39 2021
From: lengchao at huawei.com (Chao Leng)
Date: Mon, 1 Feb 2021 11:49:39 +0800
Subject: [PATCH v5 2/3] nvme-fabrics: avoid double request completion for
 nvmf_fail_nonready_command
In-Reply-To: <20210201034940.18891-1-lengchao@huawei.com>
References: <20210201034940.18891-1-lengchao@huawei.com>
Message-ID: <20210201034940.18891-3-lengchao@huawei.com>

When reconnect, the request may be completed with NVME_SC_HOST_PATH_ERROR
in nvmf_fail_nonready_command. The state of request will be changed to
MQ_RQ_IN_FLIGHT before call nvme_complete_rq. If free the request
asynchronously such as in nvme_submit_user_cmd, in extreme scenario
the request may be completed again in tear down process.
nvmf_fail_nonready_command do not need calling blk_mq_start_request
before complete the request. nvmf_fail_nonready_command should set
the state of request to MQ_RQ_COMPLETE before complete the request.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 drivers/nvme/host/fabrics.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c
index 72ac00173500..cedf9b318986 100644
--- a/drivers/nvme/host/fabrics.c
+++ b/drivers/nvme/host/fabrics.c
@@ -554,7 +554,7 @@ blk_status_t nvmf_fail_nonready_command(struct nvme_ctrl *ctrl,
 		return BLK_STS_RESOURCE;
 
 	nvme_req(rq)->status = NVME_SC_HOST_PATH_ERROR;
-	blk_mq_start_request(rq);
+	blk_mq_set_request_complete(rq);
 	nvme_complete_rq(rq);
 	return BLK_STS_OK;
 }
-- 
2.16.4



From lengchao at huawei.com  Sun Jan 31 22:49:40 2021
From: lengchao at huawei.com (Chao Leng)
Date: Mon, 1 Feb 2021 11:49:40 +0800
Subject: [PATCH v5 3/3] nvme-rdma: avoid IO error for nvme native multipath
In-Reply-To: <20210201034940.18891-1-lengchao@huawei.com>
References: <20210201034940.18891-1-lengchao@huawei.com>
Message-ID: <20210201034940.18891-4-lengchao@huawei.com>

Work with nvme native multipath, if a path related error occurs when
queue_rq call HBA drive to send request, queue_rq will return
BLK_STS_IOERR to blk-mq. The request is completed with BLK_STS_IOERR
instead of fail over to retry.
queue_rq need complete the request with NVME_SC_HOST_PATH_ERROR and set
the state of request to MQ_RQ_COMPLETE, the request will fail over to
retry if needed.

Signed-off-by: Chao Leng <lengchao at huawei.com>
---
 drivers/nvme/host/rdma.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index b7ce4f221d99..5fc113dd3302 100644
--- a/drivers/nvme/host/rdma.c
+++ b/drivers/nvme/host/rdma.c
@@ -2084,8 +2084,19 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
 
 	err = nvme_rdma_post_send(queue, sqe, req->sge, req->num_sge,
 			req->mr ? &req->reg_wr.wr : NULL);
-	if (unlikely(err))
+	if (unlikely(err)) {
+		if (err == -EIO) {
+			/*
+			 * Fail the reqest so upper layer can failover I/O
+			 * if another path is available
+			 */
+			req->status = NVME_SC_HOST_PATH_ERROR;
+			blk_mq_set_request_complete(rq);
+			nvme_rdma_complete_rq(rq);
+			return BLK_STS_OK;
+		}
 		goto err_unmap;
+	}
 
 	return BLK_STS_OK;
 
-- 
2.16.4



From lengchao at huawei.com  Sun Jan 31 22:49:37 2021
From: lengchao at huawei.com (Chao Leng)
Date: Mon, 1 Feb 2021 11:49:37 +0800
Subject: [PATCH v5 0/3] avoid double request completion and IO error
Message-ID: <20210201034940.18891-1-lengchao@huawei.com>

First, avoid double request completion for nvmf_fail_nonready_command if
the request is freed asynchronously.
Second, avoid IO error. If work with nvme native multipath, rdma HBA
drivers may failed due to failed hardware, queue_rq should failed the
request instead of returning error to block layer, So upper layer can
failover the request if another path is available.
Need set the state of request to MQ_RQ_COMPLETE when queue_rq directly
complete the request. So introduce blk_mq_set_request_complete.

V5:
	- add comment for blk_mq_set_request_complete.
	- fail the request just for -EIO returned by rdma HBA drivers.
	- delete the helper: nvme_complete_failed_req.
V4:
	- add status parameter for nvme_complete_failed_req.
	- export nvme_complete_failed_req instead of inline function.
V3:
	- complete the request just for HBA driver path related error.
V2:
	- use "switch" instead "if" to check return status.

Chao Leng (3):
  blk-mq: introduce blk_mq_set_request_complete
  nvme-fabrics: avoid double request completion for
    nvmf_fail_nonready_command
  nvme-rdma: avoid IO error for nvme native multipath

 drivers/nvme/host/fabrics.c |  2 +-
 drivers/nvme/host/rdma.c    | 13 ++++++++++++-
 include/linux/blk-mq.h      |  9 +++++++++
 3 files changed, 22 insertions(+), 2 deletions(-)

-- 
2.16.4



