forked from luck/tmp_suning_uos_patched
[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: Bhanu Prakash Gollapudi <bprakash@broadcom.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
parent
8121401313
commit
b338c785c5
@ -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,8 +1072,10 @@ int bnx2fc_process_new_cqes(struct bnx2fc_rport *tgt)
|
||||
1 - tgt->cq_curr_toggle_bit;
|
||||
}
|
||||
}
|
||||
if (num_free_sqes) {
|
||||
bnx2fc_arm_cq(tgt);
|
||||
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);
|
||||
}
|
||||
spin_unlock_bh(&tgt->cq_lock);
|
||||
|
@ -133,9 +133,9 @@ 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);
|
||||
}
|
||||
/* Arm CQ */
|
||||
bnx2fc_arm_cq(tgt);
|
||||
} else
|
||||
/* Arm CQ */
|
||||
bnx2fc_arm_cq(tgt);
|
||||
return;
|
||||
|
||||
ofld_err:
|
||||
@ -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);
|
||||
tgt->ctx_base = NULL;
|
||||
}
|
||||
|
||||
spin_lock_bh(&tgt->cq_lock);
|
||||
ctx_base_ptr = tgt->ctx_base;
|
||||
tgt->ctx_base = NULL;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user