From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: From: Sasha Levin To: "linux-kernel@vger.kernel.org" , "stable@vger.kernel.org" CC: James Smart , James Smart , Christoph Hellwig , Sasha Levin Subject: [PATCH AUTOSEL for 4.15 062/124] nvme_fcloop: disassocate local port structs Date: Mon, 19 Mar 2018 15:48:06 +0000 Message-ID: <20180319154645.11350-62-alexander.levin@microsoft.com> References: <20180319154645.11350-1-alexander.levin@microsoft.com> In-Reply-To: <20180319154645.11350-1-alexander.levin@microsoft.com> Content-Language: en-US Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Sender: linux-kernel-owner@vger.kernel.org List-ID: 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; }; =20 +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 =3D localport->private; + struct fcloop_lport_priv *lport_priv =3D localport->private; + struct fcloop_lport *lport =3D lport_priv->lport; =20 /* release any threads waiting for the unreg to complete */ complete(&lport->unreg_done); @@ -697,7 +702,7 @@ static struct nvme_fc_port_template fctemplate =3D { .max_dif_sgl_segments =3D FCLOOP_SGL_SEGS, .dma_boundary =3D FCLOOP_DMABOUND_4G, /* sizes of additional private data for data structures */ - .local_priv_sz =3D sizeof(struct fcloop_lport), + .local_priv_sz =3D sizeof(struct fcloop_lport_priv), .remote_priv_sz =3D sizeof(struct fcloop_rport), .lsrqst_priv_sz =3D sizeof(struct fcloop_lsreq), .fcprqst_priv_sz =3D sizeof(struct fcloop_ini_fcpreq), @@ -728,11 +733,17 @@ fcloop_create_local_port(struct device *dev, struct d= evice_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 =3D -ENOMEM; + + lport =3D kzalloc(sizeof(*lport), GFP_KERNEL); + if (!lport) + return -ENOMEM; =20 opts =3D kzalloc(sizeof(*opts), GFP_KERNEL); if (!opts) - return -ENOMEM; + goto out_free_lport; =20 ret =3D fcloop_parse_options(opts, buf); if (ret) @@ -752,23 +763,25 @@ fcloop_create_local_port(struct device *dev, struct d= evice_attribute *attr, =20 ret =3D nvme_fc_register_localport(&pinfo, &fctemplate, NULL, &localport)= ; if (!ret) { - unsigned long flags; - /* success */ - lport =3D localport->private; + lport_priv =3D localport->private; + lport_priv->lport =3D lport; + lport->localport =3D localport; INIT_LIST_HEAD(&lport->lport_list); =20 spin_lock_irqsave(&fcloop_lock, flags); list_add_tail(&lport->lport_list, &fcloop_lports); spin_unlock_irqrestore(&fcloop_lock, flags); - - /* mark all of the input buffer consumed */ - ret =3D count; } =20 out_free_opts: kfree(opts); +out_free_lport: + /* free only if we're going to fail */ + if (ret) + kfree(lport); + return ret ? ret : count; } =20 @@ -790,6 +803,8 @@ __wait_localport_unreg(struct fcloop_lport *lport) =20 wait_for_completion(&lport->unreg_done); =20 + kfree(lport); + return ret; } =20 --=20 2.14.1