From: Hannes Reinecke <hare@xxxxxxxx> The fc_rport_priv structure is reference counted, so we need to ensure that the reference is increased before accessing the structure. Signed-off-by: Hannes Reinecke <hare@xxxxxxxx> Signed-off-by: Saurav Kashyap <skashyap@xxxxxxxxxxx> --- drivers/scsi/qedf/qedf_els.c | 9 ++++++++- drivers/scsi/qedf/qedf_io.c | 25 +++++++++++++++++-------- drivers/scsi/qedf/qedf_main.c | 5 +++++ 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/qedf/qedf_els.c b/drivers/scsi/qedf/qedf_els.c index f1f57637..1781e73 100644 --- a/drivers/scsi/qedf/qedf_els.c +++ b/drivers/scsi/qedf/qedf_els.c @@ -378,12 +378,18 @@ void qedf_restart_rport(struct qedf_rport *fcport) spin_unlock_irqrestore(&fcport->rport_lock, flags); rdata = fcport->rdata; - if (rdata) { + if (rdata && !kref_get_unless_zero(&rdata->kref)) { + fcport->rdata = NULL; + rdata = NULL; + } + + if (rdata && rdata->rp_state == RPORT_ST_READY) { lport = fcport->qedf->lport; port_id = rdata->ids.port_id; QEDF_ERR(&(fcport->qedf->dbg_ctx), "LOGO port_id=%x.\n", port_id); fc_rport_logoff(rdata); + kref_put(&rdata->kref, fc_rport_destroy); mutex_lock(&lport->disc.disc_mutex); /* Recreate the rport and log back in */ rdata = fc_rport_create(lport, port_id); @@ -393,6 +399,7 @@ void qedf_restart_rport(struct qedf_rport *fcport) fcport->rdata = rdata; } else { mutex_unlock(&lport->disc.disc_mutex); + fcport->rdata = NULL; } } clear_bit(QEDF_RPORT_IN_RESET, &fcport->flags); diff --git a/drivers/scsi/qedf/qedf_io.c b/drivers/scsi/qedf/qedf_io.c index 57c3aa4..56d2116 100644 --- a/drivers/scsi/qedf/qedf_io.c +++ b/drivers/scsi/qedf/qedf_io.c @@ -1799,6 +1799,7 @@ int qedf_initiate_abts(struct qedf_ioreq *io_req, bool return_scsi_cmd_on_abts) goto out; } + qedf = fcport->qedf; rdata = fcport->rdata; if (!rdata || !kref_get_unless_zero(&rdata->kref)) { @@ -1808,32 +1809,31 @@ int qedf_initiate_abts(struct qedf_ioreq *io_req, bool return_scsi_cmd_on_abts) } r_a_tov = rdata->r_a_tov; - qedf = fcport->qedf; lport = qedf->lport; if (lport->state != LPORT_ST_READY || !(lport->link_up)) { QEDF_ERR(&(qedf->dbg_ctx), "link is not ready\n"); rc = 1; - goto out; + goto drop_rdata_kref; } if (atomic_read(&qedf->link_down_tmo_valid) > 0) { QEDF_ERR(&(qedf->dbg_ctx), "link_down_tmo active.\n"); rc = 1; - goto out; + goto drop_rdata_kref; } /* Ensure room on SQ */ if (!atomic_read(&fcport->free_sqes)) { QEDF_ERR(&(qedf->dbg_ctx), "No SQ entries available\n"); rc = 1; - goto out; + goto drop_rdata_kref; } if (test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) { QEDF_ERR(&qedf->dbg_ctx, "fcport is uploading.\n"); rc = 1; - goto out; + goto drop_rdata_kref; } if (!test_bit(QEDF_CMD_OUTSTANDING, &io_req->flags) || @@ -1843,7 +1843,7 @@ int qedf_initiate_abts(struct qedf_ioreq *io_req, bool return_scsi_cmd_on_abts) "cleanup or abort processing or already " "completed.\n", io_req->xid); rc = 1; - goto out; + goto drop_rdata_kref; } kref_get(&io_req->refcount); @@ -1876,6 +1876,8 @@ int qedf_initiate_abts(struct qedf_ioreq *io_req, bool return_scsi_cmd_on_abts) spin_unlock_irqrestore(&fcport->rport_lock, flags); +drop_rdata_kref: + kref_put(&rdata->kref, fc_rport_destroy); out: return rc; } @@ -2217,6 +2219,7 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd, unsigned long flags; struct fcoe_wqe *sqe; u16 sqe_idx; + struct fc_rport_priv *rdata = fcport->rdata; if (!sc_cmd) { QEDF_ERR(&(qedf->dbg_ctx), "invalid arg\n"); @@ -2230,8 +2233,13 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd, return FAILED; } - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_SCSI_TM, "portid = 0x%x " - "tm_flags = %d\n", fcport->rdata->ids.port_id, tm_flags); + if (!rdata || !kref_get_unless_zero(&rdata->kref)) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_SCSI_TM, "stale rport\n"); + return FAILED; + } + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_SCSI_TM, + "portid = 0x%x tm_flags = %d\n", + rdata->ids.port_id, tm_flags); io_req = qedf_alloc_cmd(fcport, QEDF_TASK_MGMT_CMD); if (!io_req) { @@ -2327,6 +2335,7 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd, rc = SUCCESS; } reset_tmf_err: + kref_put(&rdata->kref, fc_rport_destroy); return rc; } diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index f82b0b5..3f42684 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -1333,6 +1333,8 @@ static void qedf_upload_connection(struct qedf_ctx *qedf, static void qedf_cleanup_fcport(struct qedf_ctx *qedf, struct qedf_rport *fcport) { + struct fc_rport_priv *rdata = fcport->rdata; + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_CONN, "Cleaning up portid=%06x.\n", fcport->rdata->ids.port_id); @@ -1344,6 +1346,7 @@ static void qedf_cleanup_fcport(struct qedf_ctx *qedf, qedf_free_sq(qedf, fcport); fcport->rdata = NULL; fcport->qedf = NULL; + kref_put(&rdata->kref, fc_rport_destroy); } /** @@ -1419,6 +1422,8 @@ static void qedf_rport_event_handler(struct fc_lport *lport, break; } + /* Initial reference held on entry, so this can't fail */ + kref_get(&rdata->kref); fcport->rdata = rdata; fcport->rport = rport; -- 1.8.3.1