Commit a878185c authored by Eddie Wai's avatar Eddie Wai Committed by James Bottomley

[SCSI] bnx2i: Fixed kernel panic caused by unprotected task->sc->request deref

During session recovery, the conn_stop call will trigger a flush
to all outstanding SCSI cmds in the xmit queue.  This will set
all outstanding task->sc to NULL prior to the session_teardown
call which frees the task memory.

In the bnx2i SCSI response processing path, only the task was being checked
for NULL under the session lock before the task->sc->request dereferencing.
If there are outstanding SCSI cmd responses pending for process, the
following kernel panic can be exposed where task->sc was found to be NULL.

 Call Trace:
[   69.720205]  [<ffffffffa040d0d0>] bnx2i_process_new_cqes+0x290/0x3c0 [bnx2i]
[   69.804289]  [<ffffffffa040d233>] bnx2i_fastpath_notification+0x33/0xa0 [bnx2
i]
[   69.891490]  [<ffffffffa040d37b>] bnx2i_indicate_kcqe+0xdb/0x330 [bnx2i]
[   69.971427]  [<ffffffffa03eac5e>] service_kcqes+0x16e/0x1d0 [cnic]
[   70.045132]  [<ffffffffa03eacea>] cnic_service_bnx2x_kcq+0x2a/0x50 [cnic]
[   70.126105]  [<ffffffffa03ead53>] cnic_service_bnx2x_bh+0x43/0x140 [cnic]
[   70.207081]  [<ffffffff81060676>] tasklet_action+0x66/0x110
[   70.273521]  [<ffffffff8106025f>] __do_softirq+0xef/0x220
[   70.337887]  [<ffffffff81447ebc>] call_softirq+0x1c/0x30

This patch adds the !task->sc check and also protects the sc dereferencing
under the session lock.
Signed-off-by: default avatarEddie Wai <eddie.wai@broadcom.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent ff1d0319
...@@ -1906,18 +1906,19 @@ static int bnx2i_queue_scsi_cmd_resp(struct iscsi_session *session, ...@@ -1906,18 +1906,19 @@ static int bnx2i_queue_scsi_cmd_resp(struct iscsi_session *session,
spin_lock(&session->lock); spin_lock(&session->lock);
task = iscsi_itt_to_task(bnx2i_conn->cls_conn->dd_data, task = iscsi_itt_to_task(bnx2i_conn->cls_conn->dd_data,
cqe->itt & ISCSI_CMD_RESPONSE_INDEX); cqe->itt & ISCSI_CMD_RESPONSE_INDEX);
if (!task) { if (!task || !task->sc) {
spin_unlock(&session->lock); spin_unlock(&session->lock);
return -EINVAL; return -EINVAL;
} }
sc = task->sc; sc = task->sc;
spin_unlock(&session->lock);
if (!blk_rq_cpu_valid(sc->request)) if (!blk_rq_cpu_valid(sc->request))
cpu = smp_processor_id(); cpu = smp_processor_id();
else else
cpu = sc->request->cpu; cpu = sc->request->cpu;
spin_unlock(&session->lock);
p = &per_cpu(bnx2i_percpu, cpu); p = &per_cpu(bnx2i_percpu, cpu);
spin_lock(&p->p_work_lock); spin_lock(&p->p_work_lock);
if (unlikely(!p->iothread)) { if (unlikely(!p->iothread)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment