[PATCH AUTOSEL for 4.15 062/124] nvme_fcloop: disassocate local port structs

2018-03-19 Thread Sasha Levin
From: James Smart 

[ Upstream commit 6fda20283e55b9d288cd56822ce39fc8e64f2208 ]

The current fcloop driver gets its lport structure from the private
area co-allocated with the fc_localport. All is fine except the
teardown path, which wants to wait on the completion, which is marked
complete by the delete_localport callback performed after
unregister_localport.  The issue is, the nvme_fc transport frees the
localport structure immediately after delete_localport is called,
meaning the original routine is trying to wait on a complete that
was just freed.

Change such that a lport struct is allocated coincident with the
addition and registration of a localport. The private area of the
localport now contains just a backpointer to the real lport struct.
Now, the completion can be waited for, and after completing, the
new structure can be kfree'd.

Signed-off-by: James Smart 
Signed-off-by: Christoph Hellwig 
Signed-off-by: Sasha Levin 
---
 drivers/nvme/target/fcloop.c | 35 +--
 1 file changed, 25 insertions(+), 10 deletions(-)

diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c
index 6a018a0bd6ce..bedb66521a4a 100644
--- a/drivers/nvme/target/fcloop.c
+++ b/drivers/nvme/target/fcloop.c
@@ -204,6 +204,10 @@ struct fcloop_lport {
struct completion unreg_done;
 };
 
+struct fcloop_lport_priv {
+   struct fcloop_lport *lport;
+};
+
 struct fcloop_rport {
struct nvme_fc_remote_port *remoteport;
struct nvmet_fc_target_port *targetport;
@@ -657,7 +661,8 @@ fcloop_nport_get(struct fcloop_nport *nport)
 static void
 fcloop_localport_delete(struct nvme_fc_local_port *localport)
 {
-   struct fcloop_lport *lport = localport->private;
+   struct fcloop_lport_priv *lport_priv = localport->private;
+   struct fcloop_lport *lport = lport_priv->lport;
 
/* release any threads waiting for the unreg to complete */
complete(>unreg_done);
@@ -697,7 +702,7 @@ static struct nvme_fc_port_template fctemplate = {
.max_dif_sgl_segments   = FCLOOP_SGL_SEGS,
.dma_boundary   = FCLOOP_DMABOUND_4G,
/* sizes of additional private data for data structures */
-   .local_priv_sz  = sizeof(struct fcloop_lport),
+   .local_priv_sz  = sizeof(struct fcloop_lport_priv),
.remote_priv_sz = sizeof(struct fcloop_rport),
.lsrqst_priv_sz = sizeof(struct fcloop_lsreq),
.fcprqst_priv_sz= sizeof(struct fcloop_ini_fcpreq),
@@ -728,11 +733,17 @@ fcloop_create_local_port(struct device *dev, struct 
device_attribute *attr,
struct fcloop_ctrl_options *opts;
struct nvme_fc_local_port *localport;
struct fcloop_lport *lport;
-   int ret;
+   struct fcloop_lport_priv *lport_priv;
+   unsigned long flags;
+   int ret = -ENOMEM;
+
+   lport = kzalloc(sizeof(*lport), GFP_KERNEL);
+   if (!lport)
+   return -ENOMEM;
 
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
if (!opts)
-   return -ENOMEM;
+   goto out_free_lport;
 
ret = fcloop_parse_options(opts, buf);
if (ret)
@@ -752,23 +763,25 @@ fcloop_create_local_port(struct device *dev, struct 
device_attribute *attr,
 
ret = nvme_fc_register_localport(, , NULL, );
if (!ret) {
-   unsigned long flags;
-
/* success */
-   lport = localport->private;
+   lport_priv = localport->private;
+   lport_priv->lport = lport;
+
lport->localport = localport;
INIT_LIST_HEAD(>lport_list);
 
spin_lock_irqsave(_lock, flags);
list_add_tail(>lport_list, _lports);
spin_unlock_irqrestore(_lock, flags);
-
-   /* mark all of the input buffer consumed */
-   ret = count;
}
 
 out_free_opts:
kfree(opts);
+out_free_lport:
+   /* free only if we're going to fail */
+   if (ret)
+   kfree(lport);
+
return ret ? ret : count;
 }
 
@@ -790,6 +803,8 @@ __wait_localport_unreg(struct fcloop_lport *lport)
 
wait_for_completion(>unreg_done);
 
+   kfree(lport);
+
return ret;
 }
 
-- 
2.14.1


[PATCH AUTOSEL for 4.15 062/124] nvme_fcloop: disassocate local port structs

2018-03-19 Thread Sasha Levin
From: James Smart 

[ Upstream commit 6fda20283e55b9d288cd56822ce39fc8e64f2208 ]

The current fcloop driver gets its lport structure from the private
area co-allocated with the fc_localport. All is fine except the
teardown path, which wants to wait on the completion, which is marked
complete by the delete_localport callback performed after
unregister_localport.  The issue is, the nvme_fc transport frees the
localport structure immediately after delete_localport is called,
meaning the original routine is trying to wait on a complete that
was just freed.

Change such that a lport struct is allocated coincident with the
addition and registration of a localport. The private area of the
localport now contains just a backpointer to the real lport struct.
Now, the completion can be waited for, and after completing, the
new structure can be kfree'd.

Signed-off-by: James Smart 
Signed-off-by: Christoph Hellwig 
Signed-off-by: Sasha Levin 
---
 drivers/nvme/target/fcloop.c | 35 +--
 1 file changed, 25 insertions(+), 10 deletions(-)

diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c
index 6a018a0bd6ce..bedb66521a4a 100644
--- a/drivers/nvme/target/fcloop.c
+++ b/drivers/nvme/target/fcloop.c
@@ -204,6 +204,10 @@ struct fcloop_lport {
struct completion unreg_done;
 };
 
+struct fcloop_lport_priv {
+   struct fcloop_lport *lport;
+};
+
 struct fcloop_rport {
struct nvme_fc_remote_port *remoteport;
struct nvmet_fc_target_port *targetport;
@@ -657,7 +661,8 @@ fcloop_nport_get(struct fcloop_nport *nport)
 static void
 fcloop_localport_delete(struct nvme_fc_local_port *localport)
 {
-   struct fcloop_lport *lport = localport->private;
+   struct fcloop_lport_priv *lport_priv = localport->private;
+   struct fcloop_lport *lport = lport_priv->lport;
 
/* release any threads waiting for the unreg to complete */
complete(>unreg_done);
@@ -697,7 +702,7 @@ static struct nvme_fc_port_template fctemplate = {
.max_dif_sgl_segments   = FCLOOP_SGL_SEGS,
.dma_boundary   = FCLOOP_DMABOUND_4G,
/* sizes of additional private data for data structures */
-   .local_priv_sz  = sizeof(struct fcloop_lport),
+   .local_priv_sz  = sizeof(struct fcloop_lport_priv),
.remote_priv_sz = sizeof(struct fcloop_rport),
.lsrqst_priv_sz = sizeof(struct fcloop_lsreq),
.fcprqst_priv_sz= sizeof(struct fcloop_ini_fcpreq),
@@ -728,11 +733,17 @@ fcloop_create_local_port(struct device *dev, struct 
device_attribute *attr,
struct fcloop_ctrl_options *opts;
struct nvme_fc_local_port *localport;
struct fcloop_lport *lport;
-   int ret;
+   struct fcloop_lport_priv *lport_priv;
+   unsigned long flags;
+   int ret = -ENOMEM;
+
+   lport = kzalloc(sizeof(*lport), GFP_KERNEL);
+   if (!lport)
+   return -ENOMEM;
 
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
if (!opts)
-   return -ENOMEM;
+   goto out_free_lport;
 
ret = fcloop_parse_options(opts, buf);
if (ret)
@@ -752,23 +763,25 @@ fcloop_create_local_port(struct device *dev, struct 
device_attribute *attr,
 
ret = nvme_fc_register_localport(, , NULL, );
if (!ret) {
-   unsigned long flags;
-
/* success */
-   lport = localport->private;
+   lport_priv = localport->private;
+   lport_priv->lport = lport;
+
lport->localport = localport;
INIT_LIST_HEAD(>lport_list);
 
spin_lock_irqsave(_lock, flags);
list_add_tail(>lport_list, _lports);
spin_unlock_irqrestore(_lock, flags);
-
-   /* mark all of the input buffer consumed */
-   ret = count;
}
 
 out_free_opts:
kfree(opts);
+out_free_lport:
+   /* free only if we're going to fail */
+   if (ret)
+   kfree(lport);
+
return ret ? ret : count;
 }
 
@@ -790,6 +803,8 @@ __wait_localport_unreg(struct fcloop_lport *lport)
 
wait_for_completion(>unreg_done);
 
+   kfree(lport);
+
return ret;
 }
 
-- 
2.14.1