Commit 3cbb7a74 authored by Jayamohan Kallickal's avatar Jayamohan Kallickal Committed by James Bottomley
Browse files

[SCSI] be2iscsi: Fix for premature buffer free



This patch fixes a bug where the buffer was being freed as soon as
 submission to HW is done.

Signed-off-by: default avatarJayamohan Kallickal <jayamohank@serverengines.com>
Reviewed-by: default avatarMike Christie <michaelc@cs.wisc.edu>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent 0aa09433
Loading
Loading
Loading
Loading
+23 −1
Original line number Diff line number Diff line
@@ -488,6 +488,7 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep,
	struct be_mcc_wrb *wrb;
	struct tcp_connect_and_offload_out *ptcpcnct_out;
	unsigned short status, extd_status;
	struct be_dma_mem nonemb_cmd;
	unsigned int tag, wrb_num;
	int ret = -ENOMEM;

@@ -504,16 +505,31 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep,
	if (beiscsi_ep->ep_cid > (phba->fw_config.iscsi_cid_start +
				  phba->params.cxns_per_ctrl * 2)) {
		SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n");
		beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
		goto free_ep;
	}

	beiscsi_ep->cid_vld = 0;
	tag = mgmt_open_connection(phba, dst_addr, beiscsi_ep);
	nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev,
				sizeof(struct tcp_connect_and_offload_in),
				&nonemb_cmd.dma);
	if (nonemb_cmd.va == NULL) {
		SE_DEBUG(DBG_LVL_1,
			 "Failed to allocate memory for mgmt_open_connection"
			 "\n");
		beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
		return -ENOMEM;
	}
	nonemb_cmd.size = sizeof(struct tcp_connect_and_offload_in);
	memset(nonemb_cmd.va, 0, nonemb_cmd.size);
	tag = mgmt_open_connection(phba, dst_addr, beiscsi_ep, &nonemb_cmd);
	if (!tag) {
		SE_DEBUG(DBG_LVL_1,
			 "mgmt_open_connection Failed for cid=%d\n",
			 beiscsi_ep->ep_cid);
		beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
		pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
				    nonemb_cmd.va, nonemb_cmd.dma);
		return -EAGAIN;
	} else {
		wait_event_interruptible(phba->ctrl.mcc_wait[tag],
@@ -526,7 +542,10 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep,
		SE_DEBUG(DBG_LVL_1, "mgmt_open_connection Failed"
				    " status = %d extd_status = %d\n",
				    status, extd_status);
		beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
		free_mcc_tag(&phba->ctrl, tag);
		pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
			    nonemb_cmd.va, nonemb_cmd.dma);
		goto free_ep;
	} else {
		wrb = queue_get_wrb(mccq, wrb_num);
@@ -538,6 +557,9 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep,
		beiscsi_ep->cid_vld = 1;
		SE_DEBUG(DBG_LVL_8, "mgmt_open_connection Success\n");
	}
	beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
	pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
			    nonemb_cmd.va, nonemb_cmd.dma);
	return 0;

free_ep:
+37 −4
Original line number Diff line number Diff line
@@ -71,6 +71,7 @@ static int beiscsi_eh_abort(struct scsi_cmnd *sc)
	struct beiscsi_hba *phba;
	struct iscsi_session *session;
	struct invalidate_command_table *inv_tbl;
	struct be_dma_mem nonemb_cmd;
	unsigned int cid, tag, num_invalidate;

	cls_session = starget_to_session(scsi_target(sc->device));
@@ -101,18 +102,34 @@ static int beiscsi_eh_abort(struct scsi_cmnd *sc)
	inv_tbl->cid = cid;
	inv_tbl->icd = aborted_io_task->psgl_handle->sgl_index;
	num_invalidate = 1;
	tag = mgmt_invalidate_icds(phba, inv_tbl, num_invalidate, cid);
	nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev,
				sizeof(struct invalidate_commands_params_in),
				&nonemb_cmd.dma);
	if (nonemb_cmd.va == NULL) {
		SE_DEBUG(DBG_LVL_1,
			 "Failed to allocate memory for"
			 "mgmt_invalidate_icds\n");
		return FAILED;
	}
	nonemb_cmd.size = sizeof(struct invalidate_commands_params_in);

	tag = mgmt_invalidate_icds(phba, inv_tbl, num_invalidate,
				   cid, &nonemb_cmd);
	if (!tag) {
		shost_printk(KERN_WARNING, phba->shost,
			     "mgmt_invalidate_icds could not be"
			     " submitted\n");
		pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
				    nonemb_cmd.va, nonemb_cmd.dma);

		return FAILED;
	} else {
		wait_event_interruptible(phba->ctrl.mcc_wait[tag],
					 phba->ctrl.mcc_numtag[tag]);
		free_mcc_tag(&phba->ctrl, tag);
	}

	pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
			    nonemb_cmd.va, nonemb_cmd.dma);
	return iscsi_eh_abort(sc);
}

@@ -126,6 +143,7 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
	struct iscsi_session *session;
	struct iscsi_cls_session *cls_session;
	struct invalidate_command_table *inv_tbl;
	struct be_dma_mem nonemb_cmd;
	unsigned int cid, tag, i, num_invalidate;
	int rc = FAILED;

@@ -160,18 +178,33 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
	spin_unlock_bh(&session->lock);
	inv_tbl = phba->inv_tbl;

	tag = mgmt_invalidate_icds(phba, inv_tbl, num_invalidate, cid);
	nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev,
				sizeof(struct invalidate_commands_params_in),
				&nonemb_cmd.dma);
	if (nonemb_cmd.va == NULL) {
		SE_DEBUG(DBG_LVL_1,
			 "Failed to allocate memory for"
			 "mgmt_invalidate_icds\n");
		return FAILED;
	}
	nonemb_cmd.size = sizeof(struct invalidate_commands_params_in);
	memset(nonemb_cmd.va, 0, nonemb_cmd.size);
	tag = mgmt_invalidate_icds(phba, inv_tbl, num_invalidate,
				   cid, &nonemb_cmd);
	if (!tag) {
		shost_printk(KERN_WARNING, phba->shost,
			     "mgmt_invalidate_icds could not be"
			     " submitted\n");
		pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
				    nonemb_cmd.va, nonemb_cmd.dma);
		return FAILED;
	} else {
		wait_event_interruptible(phba->ctrl.mcc_wait[tag],
					 phba->ctrl.mcc_numtag[tag]);
		free_mcc_tag(&phba->ctrl, tag);
	}

	pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
			    nonemb_cmd.va, nonemb_cmd.dma);
	return iscsi_eh_device_reset(sc);
unlock:
	spin_unlock_bh(&session->lock);
+21 −24
Original line number Diff line number Diff line
@@ -145,9 +145,10 @@ int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute)

unsigned int  mgmt_invalidate_icds(struct beiscsi_hba *phba,
				struct invalidate_command_table *inv_tbl,
				unsigned int num_invalidate, unsigned int cid)
				unsigned int num_invalidate, unsigned int cid,
				struct be_dma_mem *nonemb_cmd)

{
	struct be_dma_mem nonemb_cmd;
	struct be_ctrl_info *ctrl = &phba->ctrl;
	struct be_mcc_wrb *wrb;
	struct be_sge *sge;
@@ -161,18 +162,7 @@ unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba,
		return tag;
	}

	nonemb_cmd.va = pci_alloc_consistent(ctrl->pdev,
				sizeof(struct invalidate_commands_params_in),
				&nonemb_cmd.dma);
	if (nonemb_cmd.va == NULL) {
		SE_DEBUG(DBG_LVL_1,
			 "Failed to alloc memory for mgmt_invalidate_icds\n");
		spin_unlock(&ctrl->mbox_lock);
		free_mcc_tag(&phba->ctrl, tag);
		return 0;
	}
	nonemb_cmd.size = sizeof(struct invalidate_commands_params_in);
	req = nonemb_cmd.va;
	req = nonemb_cmd->va;
	memset(req, 0, sizeof(*req));
	wrb = wrb_from_mccq(phba);
	sge = nonembedded_sgl(wrb);
@@ -190,15 +180,12 @@ unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba,
		req->icd_count++;
		inv_tbl++;
	}
	sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd.dma));
	sge->pa_lo = cpu_to_le32(nonemb_cmd.dma & 0xFFFFFFFF);
	sge->len = cpu_to_le32(nonemb_cmd.size);
	sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
	sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
	sge->len = cpu_to_le32(nonemb_cmd->size);

	be_mcc_notify(phba);
	spin_unlock(&ctrl->mbox_lock);
	if (nonemb_cmd.va)
		pci_free_consistent(ctrl->pdev, nonemb_cmd.size,
				    nonemb_cmd.va, nonemb_cmd.dma);
	return tag;
}

@@ -269,7 +256,9 @@ unsigned int mgmt_upload_connection(struct beiscsi_hba *phba,

int mgmt_open_connection(struct beiscsi_hba *phba,
			 struct sockaddr *dst_addr,
			 struct beiscsi_endpoint *beiscsi_ep)
			 struct beiscsi_endpoint *beiscsi_ep,
			 struct be_dma_mem *nonemb_cmd)

{
	struct hwi_controller *phwi_ctrlr;
	struct hwi_context_memory *phwi_context;
@@ -285,6 +274,7 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
	unsigned int tag = 0;
	unsigned int i;
	unsigned short cid = beiscsi_ep->ep_cid;
	struct be_sge *sge;

	phwi_ctrlr = phba->phwi_ctrlr;
	phwi_context = phwi_ctrlr->phwi_ctxt;
@@ -300,10 +290,14 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
		return tag;
	}
	wrb = wrb_from_mccq(phba);
	req = embedded_payload(wrb);
	memset(wrb, 0, sizeof(*wrb));
	sge = nonembedded_sgl(wrb);

	req = nonemb_cmd->va;
	memset(req, 0, sizeof(*req));
	wrb->tag0 |= tag;

	be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
	be_wrb_hdr_prepare(wrb, sizeof(*req), true, 1);
	be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
			   OPCODE_COMMON_ISCSI_TCP_CONNECT_AND_OFFLOAD,
			   sizeof(*req));
@@ -347,6 +341,9 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
	req->do_offload = 1;
	req->dataout_template_pa.lo = ptemplate_address->lo;
	req->dataout_template_pa.hi = ptemplate_address->hi;
	sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
	sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
	sge->len = cpu_to_le32(nonemb_cmd->size);
	be_mcc_notify(phba);
	spin_unlock(&ctrl->mbox_lock);
	return tag;
+6 −3
Original line number Diff line number Diff line
@@ -87,15 +87,18 @@ struct mcc_wrb {
};

int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute);
int mgmt_open_connection(struct beiscsi_hba *phba, struct sockaddr *dst_addr,
			 struct beiscsi_endpoint *beiscsi_ep);
int mgmt_open_connection(struct beiscsi_hba *phba,
			 struct sockaddr *dst_addr,
			 struct beiscsi_endpoint *beiscsi_ep,
			 struct be_dma_mem *nonemb_cmd);

unsigned int mgmt_upload_connection(struct beiscsi_hba *phba,
				     unsigned short cid,
				     unsigned int upload_flag);
unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba,
				struct invalidate_command_table *inv_tbl,
				unsigned int num_invalidate, unsigned int cid);
				unsigned int num_invalidate, unsigned int cid,
				struct be_dma_mem *nonemb_cmd);

struct iscsi_invalidate_connection_params_in {
	struct be_cmd_req_hdr hdr;