Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b338c785 authored by Bhanu Prakash Gollapudi's avatar Bhanu Prakash Gollapudi Committed by James Bottomley
Browse files

[SCSI] bnx2fc: Fix NULL pointer deref during arm_cq.



There exists a race condition between CQ doorbell unmap and IO completion path
that arms the CQ which causes a NULL dereference. Protect the ctx_base with
cq_lock to avoid this. Also, wait for the CQ doorbell to be successfully mapped
before arming the CQ.

Also, do not count uncolicited CQ completions for free_sqes.

Signed-off-by: default avatarBhanu Prakash Gollapudi <bprakash@broadcom.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent 81214013
Loading
Loading
Loading
Loading
+7 −3
Original line number Diff line number Diff line
@@ -1009,6 +1009,7 @@ int bnx2fc_process_new_cqes(struct bnx2fc_rport *tgt)
	u32 cq_cons;
	struct fcoe_cqe *cqe;
	u32 num_free_sqes = 0;
	u32 num_cqes = 0;
	u16 wqe;

	/*
@@ -1058,10 +1059,11 @@ int bnx2fc_process_new_cqes(struct bnx2fc_rport *tgt)
				wake_up_process(fps->iothread);
			else
				bnx2fc_process_cq_compl(tgt, wqe);
			num_free_sqes++;
		}
		cqe++;
		tgt->cq_cons_idx++;
		num_free_sqes++;
		num_cqes++;

		if (tgt->cq_cons_idx == BNX2FC_CQ_WQES_MAX) {
			tgt->cq_cons_idx = 0;
@@ -1070,7 +1072,9 @@ int bnx2fc_process_new_cqes(struct bnx2fc_rport *tgt)
				1 - tgt->cq_curr_toggle_bit;
		}
	}
	if (num_free_sqes) {
	if (num_cqes) {
		/* Arm CQ only if doorbell is mapped */
		if (tgt->ctx_base)
			bnx2fc_arm_cq(tgt);
		atomic_add(num_free_sqes, &tgt->free_sqes);
	}
+11 −8
Original line number Diff line number Diff line
@@ -133,7 +133,7 @@ static void bnx2fc_offload_session(struct fcoe_port *port,
		printk(KERN_ERR PFX "map doorbell failed - no mem\n");
		/* upload will take care of cleaning up sess resc */
		lport->tt.rport_logoff(rdata);
	}
	} else
		/* Arm CQ */
		bnx2fc_arm_cq(tgt);
	return;
@@ -806,14 +806,14 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
static void bnx2fc_free_session_resc(struct bnx2fc_hba *hba,
						struct bnx2fc_rport *tgt)
{
	void __iomem *ctx_base_ptr;

	BNX2FC_TGT_DBG(tgt, "Freeing up session resources\n");

	if (tgt->ctx_base) {
		iounmap(tgt->ctx_base);
	spin_lock_bh(&tgt->cq_lock);
	ctx_base_ptr = tgt->ctx_base;
	tgt->ctx_base = NULL;
	}

	spin_lock_bh(&tgt->cq_lock);
	/* Free LCQ */
	if (tgt->lcq) {
		dma_free_coherent(&hba->pcidev->dev, tgt->lcq_mem_size,
@@ -867,4 +867,7 @@ static void bnx2fc_free_session_resc(struct bnx2fc_hba *hba,
		tgt->sq = NULL;
	}
	spin_unlock_bh(&tgt->cq_lock);

	if (ctx_base_ptr)
		iounmap(ctx_base_ptr);
}