All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] nvmet-tcp: fix memory leak when having inflight commands on disconnect
@ 2021-05-24 11:24 elad.grupi
  2021-05-25 15:52 ` Sagi Grimberg
  2021-05-26 14:05 ` Christoph Hellwig
  0 siblings, 2 replies; 7+ messages in thread
From: elad.grupi @ 2021-05-24 11:24 UTC (permalink / raw)
  To: sagi, linux-nvme; +Cc: Elad Grupi

From: Elad Grupi <elad.grupi@dell.com>

Some nvme commands might get completed during the execution of
nvmet_tcp_release_queue_work. Those commands are being added to
resp_list on the queue and never processed after cancel_work_sync
is done, causing memory leak of the resources allocated for those commands.

Signed-off-by: Elad Grupi <elad.grupi@dell.com>
---
 drivers/nvme/target/tcp.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
index f9f34f6caf5e..3c6e36c6ed4a 100644
--- a/drivers/nvme/target/tcp.c
+++ b/drivers/nvme/target/tcp.c
@@ -1426,6 +1426,33 @@ static void nvmet_tcp_uninit_data_in_cmds(struct nvmet_tcp_queue *queue)
 	}
 }
 
+static void nvmet_tcp_free_resp_list(struct nvmet_tcp_queue *queue)
+{
+	struct list_head *p;
+	struct nvmet_tcp_cmd *cmd;
+	int c = 0;
+
+	nvmet_tcp_process_resp_list(queue);
+
+	list_for_each(p, &queue->resp_send_list) {
+		cmd = list_entry(p, struct nvmet_tcp_cmd, entry);
+		kfree(cmd->iov);
+		sgl_free(cmd->req.sg);
+		c++;
+	}
+
+	WARN_ON(c != queue->send_list_len);
+
+	if (queue->snd_cmd) {
+		kfree(queue->snd_cmd->iov);
+		sgl_free(queue->snd_cmd->req.sg);
+		c++;
+	}
+
+	pr_debug("qid %u send_list_len %d, free %d unprocessed commands\n",
+			queue->nvme_sq.qid, queue->send_list_len, c);
+}
+
 static void nvmet_tcp_release_queue_work(struct work_struct *w)
 {
 	struct nvmet_tcp_queue *queue =
@@ -1441,6 +1468,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_free_resp_list(queue);
 	sock_release(queue->sock);
 	nvmet_tcp_free_cmds(queue);
 	if (queue->hdr_digest || queue->data_digest)
-- 
2.18.2


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

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH] nvmet-tcp: fix memory leak when having inflight commands on disconnect
  2021-05-24 11:24 [PATCH] nvmet-tcp: fix memory leak when having inflight commands on disconnect elad.grupi
@ 2021-05-25 15:52 ` Sagi Grimberg
  2021-05-26 14:05 ` Christoph Hellwig
  1 sibling, 0 replies; 7+ messages in thread
From: Sagi Grimberg @ 2021-05-25 15:52 UTC (permalink / raw)
  To: elad.grupi, linux-nvme


> +static void nvmet_tcp_free_resp_list(struct nvmet_tcp_queue *queue)
> +{
> +	struct list_head *p;
> +	struct nvmet_tcp_cmd *cmd;
> +	int c = 0;
> +
> +	nvmet_tcp_process_resp_list(queue);
> +
> +	list_for_each(p, &queue->resp_send_list) {
> +		cmd = list_entry(p, struct nvmet_tcp_cmd, entry);
> +		kfree(cmd->iov);

PDUs need to be unmapped as well in case of writes. That is not
handled in nvmet_tcp_uninit_data_in_cmds ? Or is it just reads (data-out
commands)?

> +		sgl_free(cmd->req.sg);
> +		c++;
> +	}
> +
> +	WARN_ON(c != queue->send_list_len);
> +
> +	if (queue->snd_cmd) {
> +		kfree(queue->snd_cmd->iov);
> +		sgl_free(queue->snd_cmd->req.sg);
> +		c++;
> +	}
> +
> +	pr_debug("qid %u send_list_len %d, free %d unprocessed commands\n",
> +			queue->nvme_sq.qid, queue->send_list_len, c);
> +}
> +
>   static void nvmet_tcp_release_queue_work(struct work_struct *w)
>   {
>   	struct nvmet_tcp_queue *queue =
> @@ -1441,6 +1468,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_free_resp_list(queue);
>   	sock_release(queue->sock);
>   	nvmet_tcp_free_cmds(queue);
>   	if (queue->hdr_digest || queue->data_digest)
> 

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

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] nvmet-tcp: fix memory leak when having inflight commands on disconnect
  2021-05-24 11:24 [PATCH] nvmet-tcp: fix memory leak when having inflight commands on disconnect elad.grupi
  2021-05-25 15:52 ` Sagi Grimberg
@ 2021-05-26 14:05 ` Christoph Hellwig
  2021-05-27  7:38   ` Grupi, Elad
  1 sibling, 1 reply; 7+ messages in thread
From: Christoph Hellwig @ 2021-05-26 14:05 UTC (permalink / raw)
  To: elad.grupi; +Cc: sagi, linux-nvme

On Mon, May 24, 2021 at 02:24:41PM +0300, elad.grupi@dell.com wrote:
>  }
>  
> +static void nvmet_tcp_free_resp_list(struct nvmet_tcp_queue *queue)
> +{
> +	struct list_head *p;
> +	struct nvmet_tcp_cmd *cmd;
> +	int c = 0;
> +
> +	nvmet_tcp_process_resp_list(queue);
> +
> +	list_for_each(p, &queue->resp_send_list) {
> +		cmd = list_entry(p, struct nvmet_tcp_cmd, entry);

Please use list_for_each_entry instead.

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

^ permalink raw reply	[flat|nested] 7+ messages in thread

* RE: [PATCH] nvmet-tcp: fix memory leak when having inflight commands on disconnect
  2021-05-26 14:05 ` Christoph Hellwig
@ 2021-05-27  7:38   ` Grupi, Elad
  0 siblings, 0 replies; 7+ messages in thread
From: Grupi, Elad @ 2021-05-27  7:38 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: sagi, linux-nvme

Sure. I will prepare an update to the patch today.

Thanks,
Elad

-----Original Message-----
From: Christoph Hellwig <hch@infradead.org> 
Sent: Wednesday, 26 May 2021 17:05
To: Grupi, Elad
Cc: sagi@grimberg.me; linux-nvme@lists.infradead.org
Subject: Re: [PATCH] nvmet-tcp: fix memory leak when having inflight commands on disconnect


[EXTERNAL EMAIL] 

On Mon, May 24, 2021 at 02:24:41PM +0300, elad.grupi@dell.com wrote:
>  }
>  
> +static void nvmet_tcp_free_resp_list(struct nvmet_tcp_queue *queue) {
> +	struct list_head *p;
> +	struct nvmet_tcp_cmd *cmd;
> +	int c = 0;
> +
> +	nvmet_tcp_process_resp_list(queue);
> +
> +	list_for_each(p, &queue->resp_send_list) {
> +		cmd = list_entry(p, struct nvmet_tcp_cmd, entry);

Please use list_for_each_entry instead.
_______________________________________________
Linux-nvme mailing list
Linux-nvme@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-nvme

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] nvmet-tcp: fix memory leak when having inflight commands on disconnect
  2021-06-01 16:02 elad.grupi
@ 2021-06-08 23:46 ` Sagi Grimberg
  0 siblings, 0 replies; 7+ messages in thread
From: Sagi Grimberg @ 2021-06-08 23:46 UTC (permalink / raw)
  To: elad.grupi, linux-nvme


> From: Elad Grupi <elad.grupi@dell.com>
> 
> Some nvme commands might get completed during the execution of
> nvmet_tcp_release_queue_work. Those commands are being added to
> resp_list on the queue and never processed after cancel_work_sync
> is done, causing memory leak of the resources allocated for those commands.
> 
> Signed-off-by: Elad Grupi <elad.grupi@dell.com>
> ---
>   drivers/nvme/target/tcp.c | 26 ++++++++++++++++++++++++++
>   1 file changed, 26 insertions(+)
> 
> diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
> index f9f34f6caf5e..04d53b532ae2 100644
> --- a/drivers/nvme/target/tcp.c
> +++ b/drivers/nvme/target/tcp.c
> @@ -1426,6 +1426,31 @@ static void nvmet_tcp_uninit_data_in_cmds(struct nvmet_tcp_queue *queue)
>   	}
>   }
>   
> +static void nvmet_tcp_free_resp_list(struct nvmet_tcp_queue *queue)
> +{
> +	struct nvmet_tcp_cmd *cmd;
> +	int c = 0;
> +
> +	nvmet_tcp_process_resp_list(queue);
> +
> +	list_for_each_entry(cmd, &queue->resp_send_list, entry) {
> +		kfree(cmd->iov);
> +		sgl_free(cmd->req.sg);
> +		c++;
> +	}
> +
> +	WARN_ON(c != queue->send_list_len);
> +
> +	if (queue->snd_cmd) {
> +		kfree(queue->snd_cmd->iov);
> +		sgl_free(queue->snd_cmd->req.sg);
> +		c++;
> +	}
> +
> +	pr_debug("qid %u send_list_len %d, free %d unprocessed commands\n",
> +			queue->nvme_sq.qid, queue->send_list_len, c);
> +}
> +
>   static void nvmet_tcp_release_queue_work(struct work_struct *w)
>   {
>   	struct nvmet_tcp_queue *queue =
> @@ -1441,6 +1466,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_free_resp_list(queue);

Can't this be combined with nvme_tcp_free_cmds? Maybe consolidate
the sgl and iov free to something like nvme_tcp_free_cmd_data that
will free these and make it null-free-safe?

>   	sock_release(queue->sock);
>   	nvmet_tcp_free_cmds(queue);
>   	if (queue->hdr_digest || queue->data_digest)
> 

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

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH] nvmet-tcp: fix memory leak when having inflight commands on disconnect
@ 2021-06-01 16:02 elad.grupi
  2021-06-08 23:46 ` Sagi Grimberg
  0 siblings, 1 reply; 7+ messages in thread
From: elad.grupi @ 2021-06-01 16:02 UTC (permalink / raw)
  To: sagi, linux-nvme; +Cc: Elad Grupi

From: Elad Grupi <elad.grupi@dell.com>

Some nvme commands might get completed during the execution of
nvmet_tcp_release_queue_work. Those commands are being added to
resp_list on the queue and never processed after cancel_work_sync
is done, causing memory leak of the resources allocated for those commands.

Signed-off-by: Elad Grupi <elad.grupi@dell.com>
---
 drivers/nvme/target/tcp.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
index f9f34f6caf5e..04d53b532ae2 100644
--- a/drivers/nvme/target/tcp.c
+++ b/drivers/nvme/target/tcp.c
@@ -1426,6 +1426,31 @@ static void nvmet_tcp_uninit_data_in_cmds(struct nvmet_tcp_queue *queue)
 	}
 }
 
+static void nvmet_tcp_free_resp_list(struct nvmet_tcp_queue *queue)
+{
+	struct nvmet_tcp_cmd *cmd;
+	int c = 0;
+
+	nvmet_tcp_process_resp_list(queue);
+
+	list_for_each_entry(cmd, &queue->resp_send_list, entry) {
+		kfree(cmd->iov);
+		sgl_free(cmd->req.sg);
+		c++;
+	}
+
+	WARN_ON(c != queue->send_list_len);
+
+	if (queue->snd_cmd) {
+		kfree(queue->snd_cmd->iov);
+		sgl_free(queue->snd_cmd->req.sg);
+		c++;
+	}
+
+	pr_debug("qid %u send_list_len %d, free %d unprocessed commands\n",
+			queue->nvme_sq.qid, queue->send_list_len, c);
+}
+
 static void nvmet_tcp_release_queue_work(struct work_struct *w)
 {
 	struct nvmet_tcp_queue *queue =
@@ -1441,6 +1466,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_free_resp_list(queue);
 	sock_release(queue->sock);
 	nvmet_tcp_free_cmds(queue);
 	if (queue->hdr_digest || queue->data_digest)
-- 
2.18.2


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

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH] nvmet-tcp: fix memory leak when having inflight commands on disconnect
@ 2021-05-27 16:08 elad.grupi
  0 siblings, 0 replies; 7+ messages in thread
From: elad.grupi @ 2021-05-27 16:08 UTC (permalink / raw)
  To: sagi, linux-nvme; +Cc: Elad Grupi

From: Elad Grupi <elad.grupi@dell.com>

Some nvme commands might get completed during the execution of
nvmet_tcp_release_queue_work. Those commands are being added to
resp_list on the queue and never processed after cancel_work_sync
is done, causing memory leak of the resources allocated for those commands.

Signed-off-by: Elad Grupi <elad.grupi@dell.com>
---
 drivers/nvme/target/tcp.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
index f9f34f6caf5e..04d53b532ae2 100644
--- a/drivers/nvme/target/tcp.c
+++ b/drivers/nvme/target/tcp.c
@@ -1426,6 +1426,31 @@ static void nvmet_tcp_uninit_data_in_cmds(struct nvmet_tcp_queue *queue)
 	}
 }
 
+static void nvmet_tcp_free_resp_list(struct nvmet_tcp_queue *queue)
+{
+	struct nvmet_tcp_cmd *cmd;
+	int c = 0;
+
+	nvmet_tcp_process_resp_list(queue);
+
+	list_for_each_entry(cmd, &queue->resp_send_list, entry) {
+		kfree(cmd->iov);
+		sgl_free(cmd->req.sg);
+		c++;
+	}
+
+	WARN_ON(c != queue->send_list_len);
+
+	if (queue->snd_cmd) {
+		kfree(queue->snd_cmd->iov);
+		sgl_free(queue->snd_cmd->req.sg);
+		c++;
+	}
+
+	pr_debug("qid %u send_list_len %d, free %d unprocessed commands\n",
+			queue->nvme_sq.qid, queue->send_list_len, c);
+}
+
 static void nvmet_tcp_release_queue_work(struct work_struct *w)
 {
 	struct nvmet_tcp_queue *queue =
@@ -1441,6 +1466,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_free_resp_list(queue);
 	sock_release(queue->sock);
 	nvmet_tcp_free_cmds(queue);
 	if (queue->hdr_digest || queue->data_digest)
-- 
2.18.2


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

^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2021-06-08 23:46 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-24 11:24 [PATCH] nvmet-tcp: fix memory leak when having inflight commands on disconnect elad.grupi
2021-05-25 15:52 ` Sagi Grimberg
2021-05-26 14:05 ` Christoph Hellwig
2021-05-27  7:38   ` Grupi, Elad
2021-05-27 16:08 elad.grupi
2021-06-01 16:02 elad.grupi
2021-06-08 23:46 ` Sagi Grimberg

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.