scsi: iscsi: Rel ref after iscsi_lookup_endpoint()
[ Upstream commit 9e5fe1700896c85040943fdc0d3fee0dd3e0d36f ] Subsequent commits allow the kernel to do ep_disconnect. In that case we will have to get a proper refcount on the ep so one thread does not delete it from under another. Link: https://lore.kernel.org/r/20210525181821.7617-7-michael.christie@oracle.com Reviewed-by: Lee Duncan <lduncan@suse.com> Signed-off-by: Mike Christie <michael.christie@oracle.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
22608545b8
commit
8125738967
@@ -499,6 +499,7 @@ iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session,
|
|||||||
iser_conn->iscsi_conn = conn;
|
iser_conn->iscsi_conn = conn;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
iscsi_put_endpoint(ep);
|
||||||
mutex_unlock(&iser_conn->state_mutex);
|
mutex_unlock(&iser_conn->state_mutex);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
@@ -182,6 +182,7 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session,
|
|||||||
struct beiscsi_endpoint *beiscsi_ep;
|
struct beiscsi_endpoint *beiscsi_ep;
|
||||||
struct iscsi_endpoint *ep;
|
struct iscsi_endpoint *ep;
|
||||||
uint16_t cri_index;
|
uint16_t cri_index;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
ep = iscsi_lookup_endpoint(transport_fd);
|
ep = iscsi_lookup_endpoint(transport_fd);
|
||||||
if (!ep)
|
if (!ep)
|
||||||
@@ -189,15 +190,17 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session,
|
|||||||
|
|
||||||
beiscsi_ep = ep->dd_data;
|
beiscsi_ep = ep->dd_data;
|
||||||
|
|
||||||
if (iscsi_conn_bind(cls_session, cls_conn, is_leading))
|
if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) {
|
||||||
return -EINVAL;
|
rc = -EINVAL;
|
||||||
|
goto put_ep;
|
||||||
|
}
|
||||||
|
|
||||||
if (beiscsi_ep->phba != phba) {
|
if (beiscsi_ep->phba != phba) {
|
||||||
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
|
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
|
||||||
"BS_%d : beiscsi_ep->hba=%p not equal to phba=%p\n",
|
"BS_%d : beiscsi_ep->hba=%p not equal to phba=%p\n",
|
||||||
beiscsi_ep->phba, phba);
|
beiscsi_ep->phba, phba);
|
||||||
|
rc = -EEXIST;
|
||||||
return -EEXIST;
|
goto put_ep;
|
||||||
}
|
}
|
||||||
cri_index = BE_GET_CRI_FROM_CID(beiscsi_ep->ep_cid);
|
cri_index = BE_GET_CRI_FROM_CID(beiscsi_ep->ep_cid);
|
||||||
if (phba->conn_table[cri_index]) {
|
if (phba->conn_table[cri_index]) {
|
||||||
@@ -209,7 +212,8 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session,
|
|||||||
beiscsi_ep->ep_cid,
|
beiscsi_ep->ep_cid,
|
||||||
beiscsi_conn,
|
beiscsi_conn,
|
||||||
phba->conn_table[cri_index]);
|
phba->conn_table[cri_index]);
|
||||||
return -EINVAL;
|
rc = -EINVAL;
|
||||||
|
goto put_ep;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,7 +230,10 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session,
|
|||||||
"BS_%d : cid %d phba->conn_table[%u]=%p\n",
|
"BS_%d : cid %d phba->conn_table[%u]=%p\n",
|
||||||
beiscsi_ep->ep_cid, cri_index, beiscsi_conn);
|
beiscsi_ep->ep_cid, cri_index, beiscsi_conn);
|
||||||
phba->conn_table[cri_index] = beiscsi_conn;
|
phba->conn_table[cri_index] = beiscsi_conn;
|
||||||
return 0;
|
|
||||||
|
put_ep:
|
||||||
|
iscsi_put_endpoint(ep);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int beiscsi_iface_create_ipv4(struct beiscsi_hba *phba)
|
static int beiscsi_iface_create_ipv4(struct beiscsi_hba *phba)
|
||||||
|
@@ -1422,17 +1422,23 @@ static int bnx2i_conn_bind(struct iscsi_cls_session *cls_session,
|
|||||||
* Forcefully terminate all in progress connection recovery at the
|
* Forcefully terminate all in progress connection recovery at the
|
||||||
* earliest, either in bind(), send_pdu(LOGIN), or conn_start()
|
* earliest, either in bind(), send_pdu(LOGIN), or conn_start()
|
||||||
*/
|
*/
|
||||||
if (bnx2i_adapter_ready(hba))
|
if (bnx2i_adapter_ready(hba)) {
|
||||||
return -EIO;
|
ret_code = -EIO;
|
||||||
|
goto put_ep;
|
||||||
|
}
|
||||||
|
|
||||||
bnx2i_ep = ep->dd_data;
|
bnx2i_ep = ep->dd_data;
|
||||||
if ((bnx2i_ep->state == EP_STATE_TCP_FIN_RCVD) ||
|
if ((bnx2i_ep->state == EP_STATE_TCP_FIN_RCVD) ||
|
||||||
(bnx2i_ep->state == EP_STATE_TCP_RST_RCVD))
|
(bnx2i_ep->state == EP_STATE_TCP_RST_RCVD)) {
|
||||||
/* Peer disconnect via' FIN or RST */
|
/* Peer disconnect via' FIN or RST */
|
||||||
return -EINVAL;
|
ret_code = -EINVAL;
|
||||||
|
goto put_ep;
|
||||||
|
}
|
||||||
|
|
||||||
if (iscsi_conn_bind(cls_session, cls_conn, is_leading))
|
if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) {
|
||||||
return -EINVAL;
|
ret_code = -EINVAL;
|
||||||
|
goto put_ep;
|
||||||
|
}
|
||||||
|
|
||||||
if (bnx2i_ep->hba != hba) {
|
if (bnx2i_ep->hba != hba) {
|
||||||
/* Error - TCP connection does not belong to this device
|
/* Error - TCP connection does not belong to this device
|
||||||
@@ -1443,7 +1449,8 @@ static int bnx2i_conn_bind(struct iscsi_cls_session *cls_session,
|
|||||||
iscsi_conn_printk(KERN_ALERT, cls_conn->dd_data,
|
iscsi_conn_printk(KERN_ALERT, cls_conn->dd_data,
|
||||||
"belong to hba (%s)\n",
|
"belong to hba (%s)\n",
|
||||||
hba->netdev->name);
|
hba->netdev->name);
|
||||||
return -EEXIST;
|
ret_code = -EEXIST;
|
||||||
|
goto put_ep;
|
||||||
}
|
}
|
||||||
bnx2i_ep->conn = bnx2i_conn;
|
bnx2i_ep->conn = bnx2i_conn;
|
||||||
bnx2i_conn->ep = bnx2i_ep;
|
bnx2i_conn->ep = bnx2i_ep;
|
||||||
@@ -1460,6 +1467,8 @@ static int bnx2i_conn_bind(struct iscsi_cls_session *cls_session,
|
|||||||
bnx2i_put_rq_buf(bnx2i_conn, 0);
|
bnx2i_put_rq_buf(bnx2i_conn, 0);
|
||||||
|
|
||||||
bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE);
|
bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE);
|
||||||
|
put_ep:
|
||||||
|
iscsi_put_endpoint(ep);
|
||||||
return ret_code;
|
return ret_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2690,11 +2690,13 @@ int cxgbi_bind_conn(struct iscsi_cls_session *cls_session,
|
|||||||
err = csk->cdev->csk_ddp_setup_pgidx(csk, csk->tid,
|
err = csk->cdev->csk_ddp_setup_pgidx(csk, csk->tid,
|
||||||
ppm->tformat.pgsz_idx_dflt);
|
ppm->tformat.pgsz_idx_dflt);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
goto put_ep;
|
||||||
|
|
||||||
err = iscsi_conn_bind(cls_session, cls_conn, is_leading);
|
err = iscsi_conn_bind(cls_session, cls_conn, is_leading);
|
||||||
if (err)
|
if (err) {
|
||||||
return -EINVAL;
|
err = -EINVAL;
|
||||||
|
goto put_ep;
|
||||||
|
}
|
||||||
|
|
||||||
/* calculate the tag idx bits needed for this conn based on cmds_max */
|
/* calculate the tag idx bits needed for this conn based on cmds_max */
|
||||||
cconn->task_idx_bits = (__ilog2_u32(conn->session->cmds_max - 1)) + 1;
|
cconn->task_idx_bits = (__ilog2_u32(conn->session->cmds_max - 1)) + 1;
|
||||||
@@ -2715,7 +2717,9 @@ int cxgbi_bind_conn(struct iscsi_cls_session *cls_session,
|
|||||||
/* init recv engine */
|
/* init recv engine */
|
||||||
iscsi_tcp_hdr_recv_prep(tcp_conn);
|
iscsi_tcp_hdr_recv_prep(tcp_conn);
|
||||||
|
|
||||||
return 0;
|
put_ep:
|
||||||
|
iscsi_put_endpoint(ep);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(cxgbi_bind_conn);
|
EXPORT_SYMBOL_GPL(cxgbi_bind_conn);
|
||||||
|
|
||||||
|
@@ -387,6 +387,7 @@ static int qedi_conn_bind(struct iscsi_cls_session *cls_session,
|
|||||||
struct qedi_ctx *qedi = iscsi_host_priv(shost);
|
struct qedi_ctx *qedi = iscsi_host_priv(shost);
|
||||||
struct qedi_endpoint *qedi_ep;
|
struct qedi_endpoint *qedi_ep;
|
||||||
struct iscsi_endpoint *ep;
|
struct iscsi_endpoint *ep;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
ep = iscsi_lookup_endpoint(transport_fd);
|
ep = iscsi_lookup_endpoint(transport_fd);
|
||||||
if (!ep)
|
if (!ep)
|
||||||
@@ -394,11 +395,16 @@ static int qedi_conn_bind(struct iscsi_cls_session *cls_session,
|
|||||||
|
|
||||||
qedi_ep = ep->dd_data;
|
qedi_ep = ep->dd_data;
|
||||||
if ((qedi_ep->state == EP_STATE_TCP_FIN_RCVD) ||
|
if ((qedi_ep->state == EP_STATE_TCP_FIN_RCVD) ||
|
||||||
(qedi_ep->state == EP_STATE_TCP_RST_RCVD))
|
(qedi_ep->state == EP_STATE_TCP_RST_RCVD)) {
|
||||||
return -EINVAL;
|
rc = -EINVAL;
|
||||||
|
goto put_ep;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) {
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto put_ep;
|
||||||
|
}
|
||||||
|
|
||||||
if (iscsi_conn_bind(cls_session, cls_conn, is_leading))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
qedi_ep->conn = qedi_conn;
|
qedi_ep->conn = qedi_conn;
|
||||||
qedi_conn->ep = qedi_ep;
|
qedi_conn->ep = qedi_ep;
|
||||||
@@ -408,13 +414,18 @@ static int qedi_conn_bind(struct iscsi_cls_session *cls_session,
|
|||||||
qedi_conn->cmd_cleanup_req = 0;
|
qedi_conn->cmd_cleanup_req = 0;
|
||||||
qedi_conn->cmd_cleanup_cmpl = 0;
|
qedi_conn->cmd_cleanup_cmpl = 0;
|
||||||
|
|
||||||
if (qedi_bind_conn_to_iscsi_cid(qedi, qedi_conn))
|
if (qedi_bind_conn_to_iscsi_cid(qedi, qedi_conn)) {
|
||||||
return -EINVAL;
|
rc = -EINVAL;
|
||||||
|
goto put_ep;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
spin_lock_init(&qedi_conn->tmf_work_lock);
|
spin_lock_init(&qedi_conn->tmf_work_lock);
|
||||||
INIT_LIST_HEAD(&qedi_conn->tmf_work_list);
|
INIT_LIST_HEAD(&qedi_conn->tmf_work_list);
|
||||||
init_waitqueue_head(&qedi_conn->wait_queue);
|
init_waitqueue_head(&qedi_conn->wait_queue);
|
||||||
return 0;
|
put_ep:
|
||||||
|
iscsi_put_endpoint(ep);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int qedi_iscsi_update_conn(struct qedi_ctx *qedi,
|
static int qedi_iscsi_update_conn(struct qedi_ctx *qedi,
|
||||||
|
@@ -3238,6 +3238,7 @@ static int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session,
|
|||||||
conn = cls_conn->dd_data;
|
conn = cls_conn->dd_data;
|
||||||
qla_conn = conn->dd_data;
|
qla_conn = conn->dd_data;
|
||||||
qla_conn->qla_ep = ep->dd_data;
|
qla_conn->qla_ep = ep->dd_data;
|
||||||
|
iscsi_put_endpoint(ep);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -266,9 +266,20 @@ void iscsi_destroy_endpoint(struct iscsi_endpoint *ep)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(iscsi_destroy_endpoint);
|
EXPORT_SYMBOL_GPL(iscsi_destroy_endpoint);
|
||||||
|
|
||||||
|
void iscsi_put_endpoint(struct iscsi_endpoint *ep)
|
||||||
|
{
|
||||||
|
put_device(&ep->dev);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(iscsi_put_endpoint);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* iscsi_lookup_endpoint - get ep from handle
|
||||||
|
* @handle: endpoint handle
|
||||||
|
*
|
||||||
|
* Caller must do a iscsi_put_endpoint.
|
||||||
|
*/
|
||||||
struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle)
|
struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle)
|
||||||
{
|
{
|
||||||
struct iscsi_endpoint *ep;
|
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
|
||||||
dev = class_find_device(&iscsi_endpoint_class, NULL, &handle,
|
dev = class_find_device(&iscsi_endpoint_class, NULL, &handle,
|
||||||
@@ -276,13 +287,7 @@ struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle)
|
|||||||
if (!dev)
|
if (!dev)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
ep = iscsi_dev_to_endpoint(dev);
|
return iscsi_dev_to_endpoint(dev);
|
||||||
/*
|
|
||||||
* we can drop this now because the interface will prevent
|
|
||||||
* removals and lookups from racing.
|
|
||||||
*/
|
|
||||||
put_device(dev);
|
|
||||||
return ep;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint);
|
EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint);
|
||||||
|
|
||||||
@@ -2983,6 +2988,7 @@ static int iscsi_if_ep_disconnect(struct iscsi_transport *transport,
|
|||||||
}
|
}
|
||||||
|
|
||||||
transport->ep_disconnect(ep);
|
transport->ep_disconnect(ep);
|
||||||
|
iscsi_put_endpoint(ep);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3008,6 +3014,7 @@ iscsi_if_transport_ep(struct iscsi_transport *transport,
|
|||||||
|
|
||||||
ev->r.retcode = transport->ep_poll(ep,
|
ev->r.retcode = transport->ep_poll(ep,
|
||||||
ev->u.ep_poll.timeout_ms);
|
ev->u.ep_poll.timeout_ms);
|
||||||
|
iscsi_put_endpoint(ep);
|
||||||
break;
|
break;
|
||||||
case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT:
|
case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT:
|
||||||
rc = iscsi_if_ep_disconnect(transport,
|
rc = iscsi_if_ep_disconnect(transport,
|
||||||
@@ -3691,6 +3698,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
|
|||||||
ev->u.c_bound_session.initial_cmdsn,
|
ev->u.c_bound_session.initial_cmdsn,
|
||||||
ev->u.c_bound_session.cmds_max,
|
ev->u.c_bound_session.cmds_max,
|
||||||
ev->u.c_bound_session.queue_depth);
|
ev->u.c_bound_session.queue_depth);
|
||||||
|
iscsi_put_endpoint(ep);
|
||||||
break;
|
break;
|
||||||
case ISCSI_UEVENT_DESTROY_SESSION:
|
case ISCSI_UEVENT_DESTROY_SESSION:
|
||||||
session = iscsi_session_lookup(ev->u.d_session.sid);
|
session = iscsi_session_lookup(ev->u.d_session.sid);
|
||||||
@@ -3762,6 +3770,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
|
|||||||
mutex_lock(&conn->ep_mutex);
|
mutex_lock(&conn->ep_mutex);
|
||||||
conn->ep = ep;
|
conn->ep = ep;
|
||||||
mutex_unlock(&conn->ep_mutex);
|
mutex_unlock(&conn->ep_mutex);
|
||||||
|
iscsi_put_endpoint(ep);
|
||||||
} else
|
} else
|
||||||
iscsi_cls_conn_printk(KERN_ERR, conn,
|
iscsi_cls_conn_printk(KERN_ERR, conn,
|
||||||
"Could not set ep conn "
|
"Could not set ep conn "
|
||||||
|
@@ -444,6 +444,7 @@ extern int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time);
|
|||||||
extern struct iscsi_endpoint *iscsi_create_endpoint(int dd_size);
|
extern struct iscsi_endpoint *iscsi_create_endpoint(int dd_size);
|
||||||
extern void iscsi_destroy_endpoint(struct iscsi_endpoint *ep);
|
extern void iscsi_destroy_endpoint(struct iscsi_endpoint *ep);
|
||||||
extern struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle);
|
extern struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle);
|
||||||
|
extern void iscsi_put_endpoint(struct iscsi_endpoint *ep);
|
||||||
extern int iscsi_block_scsi_eh(struct scsi_cmnd *cmd);
|
extern int iscsi_block_scsi_eh(struct scsi_cmnd *cmd);
|
||||||
extern struct iscsi_iface *iscsi_create_iface(struct Scsi_Host *shost,
|
extern struct iscsi_iface *iscsi_create_iface(struct Scsi_Host *shost,
|
||||||
struct iscsi_transport *t,
|
struct iscsi_transport *t,
|
||||||
|
Reference in New Issue
Block a user