Commit 56efc304 authored by Hannes Reinecke's avatar Hannes Reinecke Committed by Martin K. Petersen
Browse files

scsi: qedf: fc_rport_priv reference counting fixes



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: default avatarHannes Reinecke <hare@suse.com>
Signed-off-by: default avatarSaurav Kashyap <skashyap@marvell.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 6f15d0c0
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -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);
+17 −8
Original line number Diff line number Diff line
@@ -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 @@ no_flush:
		rc = SUCCESS;
	}
reset_tmf_err:
	kref_put(&rdata->kref, fc_rport_destroy);
	return rc;
}

+5 −0
Original line number Diff line number Diff line
@@ -1334,6 +1334,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);

@@ -1345,6 +1347,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);
}

/**
@@ -1420,6 +1423,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;