lkml.org 
[lkml]   [2018]   [Mar]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH AUTOSEL for 4.15 062/124] nvme_fcloop: disassocate local port structs
    Date
    From: James Smart <jsmart2021@gmail.com>

    [ 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 <james.smart@broadcom.com>
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
    ---
    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(&lport->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(&pinfo, &fctemplate, NULL, &localport);
    if (!ret) {
    - unsigned long flags;
    -
    /* success */
    - lport = localport->private;
    + lport_priv = localport->private;
    + lport_priv->lport = lport;
    +
    lport->localport = localport;
    INIT_LIST_HEAD(&lport->lport_list);

    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 = 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(&lport->unreg_done);

    + kfree(lport);
    +
    return ret;
    }

    --
    2.14.1
    \
     
     \ /
      Last update: 2018-03-19 16:50    [W:4.087 / U:0.028 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site