nvme-fcloop: fix port deletes and callbacks
Now that there are potentially long delays between when a remoteport or targetport delete calls is made and when the callback occurs (dev_loss_tmo timeout), no longer block in the delete routines and move the final nport puts to the callbacks. Moved the fcloop_nport_get/put/free routines to avoid forward declarations. Ensure port_info structs used in registrations are nulled in case fields are not set (ex: devloss_tmo values). Signed-off-by: James Smart <james.smart@broadcom.com> Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
parent
6b71f9e1e8
commit
fddc9923c6
|
@ -224,8 +224,6 @@ struct fcloop_nport {
|
||||||
struct fcloop_lport *lport;
|
struct fcloop_lport *lport;
|
||||||
struct list_head nport_list;
|
struct list_head nport_list;
|
||||||
struct kref ref;
|
struct kref ref;
|
||||||
struct completion rport_unreg_done;
|
|
||||||
struct completion tport_unreg_done;
|
|
||||||
u64 node_name;
|
u64 node_name;
|
||||||
u64 port_name;
|
u64 port_name;
|
||||||
u32 port_role;
|
u32 port_role;
|
||||||
|
@ -630,6 +628,32 @@ fcloop_fcp_abort(struct nvme_fc_local_port *localport,
|
||||||
schedule_work(&inireq->iniwork);
|
schedule_work(&inireq->iniwork);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fcloop_nport_free(struct kref *ref)
|
||||||
|
{
|
||||||
|
struct fcloop_nport *nport =
|
||||||
|
container_of(ref, struct fcloop_nport, ref);
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&fcloop_lock, flags);
|
||||||
|
list_del(&nport->nport_list);
|
||||||
|
spin_unlock_irqrestore(&fcloop_lock, flags);
|
||||||
|
|
||||||
|
kfree(nport);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fcloop_nport_put(struct fcloop_nport *nport)
|
||||||
|
{
|
||||||
|
kref_put(&nport->ref, fcloop_nport_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
fcloop_nport_get(struct fcloop_nport *nport)
|
||||||
|
{
|
||||||
|
return kref_get_unless_zero(&nport->ref);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fcloop_localport_delete(struct nvme_fc_local_port *localport)
|
fcloop_localport_delete(struct nvme_fc_local_port *localport)
|
||||||
{
|
{
|
||||||
|
@ -644,8 +668,7 @@ fcloop_remoteport_delete(struct nvme_fc_remote_port *remoteport)
|
||||||
{
|
{
|
||||||
struct fcloop_rport *rport = remoteport->private;
|
struct fcloop_rport *rport = remoteport->private;
|
||||||
|
|
||||||
/* release any threads waiting for the unreg to complete */
|
fcloop_nport_put(rport->nport);
|
||||||
complete(&rport->nport->rport_unreg_done);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -653,8 +676,7 @@ fcloop_targetport_delete(struct nvmet_fc_target_port *targetport)
|
||||||
{
|
{
|
||||||
struct fcloop_tport *tport = targetport->private;
|
struct fcloop_tport *tport = targetport->private;
|
||||||
|
|
||||||
/* release any threads waiting for the unreg to complete */
|
fcloop_nport_put(tport->nport);
|
||||||
complete(&tport->nport->tport_unreg_done);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define FCLOOP_HW_QUEUES 4
|
#define FCLOOP_HW_QUEUES 4
|
||||||
|
@ -722,6 +744,7 @@ fcloop_create_local_port(struct device *dev, struct device_attribute *attr,
|
||||||
goto out_free_opts;
|
goto out_free_opts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memset(&pinfo, 0, sizeof(pinfo));
|
||||||
pinfo.node_name = opts->wwnn;
|
pinfo.node_name = opts->wwnn;
|
||||||
pinfo.port_name = opts->wwpn;
|
pinfo.port_name = opts->wwpn;
|
||||||
pinfo.port_role = opts->roles;
|
pinfo.port_role = opts->roles;
|
||||||
|
@ -804,32 +827,6 @@ fcloop_delete_local_port(struct device *dev, struct device_attribute *attr,
|
||||||
return ret ? ret : count;
|
return ret ? ret : count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
fcloop_nport_free(struct kref *ref)
|
|
||||||
{
|
|
||||||
struct fcloop_nport *nport =
|
|
||||||
container_of(ref, struct fcloop_nport, ref);
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&fcloop_lock, flags);
|
|
||||||
list_del(&nport->nport_list);
|
|
||||||
spin_unlock_irqrestore(&fcloop_lock, flags);
|
|
||||||
|
|
||||||
kfree(nport);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
fcloop_nport_put(struct fcloop_nport *nport)
|
|
||||||
{
|
|
||||||
kref_put(&nport->ref, fcloop_nport_free);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
fcloop_nport_get(struct fcloop_nport *nport)
|
|
||||||
{
|
|
||||||
return kref_get_unless_zero(&nport->ref);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct fcloop_nport *
|
static struct fcloop_nport *
|
||||||
fcloop_alloc_nport(const char *buf, size_t count, bool remoteport)
|
fcloop_alloc_nport(const char *buf, size_t count, bool remoteport)
|
||||||
{
|
{
|
||||||
|
@ -938,6 +935,7 @@ fcloop_create_remote_port(struct device *dev, struct device_attribute *attr,
|
||||||
if (!nport)
|
if (!nport)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
|
memset(&pinfo, 0, sizeof(pinfo));
|
||||||
pinfo.node_name = nport->node_name;
|
pinfo.node_name = nport->node_name;
|
||||||
pinfo.port_name = nport->port_name;
|
pinfo.port_name = nport->port_name;
|
||||||
pinfo.port_role = nport->port_role;
|
pinfo.port_role = nport->port_role;
|
||||||
|
@ -979,24 +977,12 @@ __unlink_remote_port(struct fcloop_nport *nport)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
__wait_remoteport_unreg(struct fcloop_nport *nport, struct fcloop_rport *rport)
|
__remoteport_unreg(struct fcloop_nport *nport, struct fcloop_rport *rport)
|
||||||
{
|
{
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!rport)
|
if (!rport)
|
||||||
return -EALREADY;
|
return -EALREADY;
|
||||||
|
|
||||||
init_completion(&nport->rport_unreg_done);
|
return nvme_fc_unregister_remoteport(rport->remoteport);
|
||||||
|
|
||||||
ret = nvme_fc_unregister_remoteport(rport->remoteport);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
wait_for_completion(&nport->rport_unreg_done);
|
|
||||||
|
|
||||||
fcloop_nport_put(nport);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
|
@ -1029,7 +1015,7 @@ fcloop_delete_remote_port(struct device *dev, struct device_attribute *attr,
|
||||||
if (!nport)
|
if (!nport)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
ret = __wait_remoteport_unreg(nport, rport);
|
ret = __remoteport_unreg(nport, rport);
|
||||||
|
|
||||||
return ret ? ret : count;
|
return ret ? ret : count;
|
||||||
}
|
}
|
||||||
|
@ -1086,24 +1072,12 @@ __unlink_target_port(struct fcloop_nport *nport)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
__wait_targetport_unreg(struct fcloop_nport *nport, struct fcloop_tport *tport)
|
__targetport_unreg(struct fcloop_nport *nport, struct fcloop_tport *tport)
|
||||||
{
|
{
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!tport)
|
if (!tport)
|
||||||
return -EALREADY;
|
return -EALREADY;
|
||||||
|
|
||||||
init_completion(&nport->tport_unreg_done);
|
return nvmet_fc_unregister_targetport(tport->targetport);
|
||||||
|
|
||||||
ret = nvmet_fc_unregister_targetport(tport->targetport);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
wait_for_completion(&nport->tport_unreg_done);
|
|
||||||
|
|
||||||
fcloop_nport_put(nport);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
|
@ -1136,7 +1110,7 @@ fcloop_delete_target_port(struct device *dev, struct device_attribute *attr,
|
||||||
if (!nport)
|
if (!nport)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
ret = __wait_targetport_unreg(nport, tport);
|
ret = __targetport_unreg(nport, tport);
|
||||||
|
|
||||||
return ret ? ret : count;
|
return ret ? ret : count;
|
||||||
}
|
}
|
||||||
|
@ -1223,11 +1197,11 @@ static void __exit fcloop_exit(void)
|
||||||
|
|
||||||
spin_unlock_irqrestore(&fcloop_lock, flags);
|
spin_unlock_irqrestore(&fcloop_lock, flags);
|
||||||
|
|
||||||
ret = __wait_targetport_unreg(nport, tport);
|
ret = __targetport_unreg(nport, tport);
|
||||||
if (ret)
|
if (ret)
|
||||||
pr_warn("%s: Failed deleting target port\n", __func__);
|
pr_warn("%s: Failed deleting target port\n", __func__);
|
||||||
|
|
||||||
ret = __wait_remoteport_unreg(nport, rport);
|
ret = __remoteport_unreg(nport, rport);
|
||||||
if (ret)
|
if (ret)
|
||||||
pr_warn("%s: Failed deleting remote port\n", __func__);
|
pr_warn("%s: Failed deleting remote port\n", __func__);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue