[PATCH scsi] add NULL checking for pointer rq_disk

From: Li Zhong
Date: Wed Apr 11 2012 - 22:02:15 EST


This patch tries to fix following oops during machine booting:

[ 0.770359] Unable to handle kernel paging request for data at address 0x00000278
[ 0.770368] Faulting instruction address: 0xc0000000003fa800
[ 0.770377] Oops: Kernel access of bad area, sig: 11 [#1]
[ 0.770383] PREEMPT SMP NR_CPUS=8 NUMA pSeries
[ 0.770395] Modules linked in:
[ 0.770402] NIP: c0000000003fa800 LR: c0000000003fa7e4 CTR: c00000000004d994
[ 0.785467] REGS: c00000004ecf3990 TRAP: 0300 Not tainted (3.4.0-rc2)
[ 0.785474] MSR: 8000000000009032 <SF,EE,ME,IR,DR,RI> CR: 28000082 XER: 0000000c
[ 0.785499] SOFTE: 1
[ 0.785503] CFAR: 0000000000004ffc
[ 0.785509] DAR: 0000000000000278, DSISR: 40000000
[ 0.785516] TASK = c00000004ed7af30[1016] 'scsi_eh_0' THREAD: c00000004ecf0000 CPU: 1
[ 0.785526] GPR00: c0000000003fa7e4 c00000004ecf3c10 c000000000a7de08 c00000004ecf3c80
[ 0.785543] GPR04: 0000000000000000 0000000000000020 0000000000000000 ffffffffffffffff
[ 0.785560] GPR08: 0000000000000001 0000000000000000 c000000000aa3e70 c00000004ecf0000
[ 0.785577] GPR12: 0000000000000002 c000000007578280 0000000002080000 c000000000814f00
[ 0.785595] GPR16: c000000000811470 0000000000000000 000000000023e000 00000000029aa1c8
[ 0.785612] GPR20: c000000000929f58 00000000029a9f58 0000000001b5f8f0 0000000000000000
[ 0.785629] GPR24: 0000000000000000 c000000000814448 00000000000009c4 00000000ffffffff
[ 0.802565] GPR28: c00000004ecf3c80 c00000008e80e800 c000000000a0e438 c00000004e54fa00
[ 0.802588] NIP [c0000000003fa800] .scsi_send_eh_cmnd+0x80/0x318
[ 0.802596] LR [c0000000003fa7e4] .scsi_send_eh_cmnd+0x64/0x318
[ 0.802603] Call Trace:
[ 0.802610] [c00000004ecf3c10] [c0000000003fa7e4] .scsi_send_eh_cmnd+0x64/0x318 (unreliable)
[ 0.802624] [c00000004ecf3d60] [c0000000003fb318] .scsi_eh_get_sense+0x70/0xf0
[ 0.802635] [c00000004ecf3e00] [c0000000003fb920] .scsi_error_handler+0x130/0x434
[ 0.802648] [c00000004ecf3ed0] [c000000000087be8] .kthread+0xb4/0xc0
[ 0.802659] [c00000004ecf3f90] [c00000000001da04] .kernel_thread+0x54/0x70
[ 0.802669] Instruction dump:
[ 0.802675] e87e8078 3b810070 ebbf0000 e8c500b8 4bc64c39 60000000 e93f0080 38800000
[ 0.802697] 38a00020 7f83e378 ebbd0000 e92900b8 <e9290278> eb290000 4bc3c725 60000000
[ 0.802725] ---[ end trace baf2215814af1bc0 ]---

The reason is that the scsi_cmd_to_driver() is trying to dereferencing a
NULL rq_disk pointer.

This patch lets scsi_cmd_to_driver() return NULL if rq_disk is NULL, and
also changes the users of this function to check the return value.

Then I also saw it reported here in bugzilla, where rocko described his
solution, which is almost the same as this patch:
https://bugzilla.kernel.org/show_bug.cgi?id=43085

Reported-by: Paul E. McKenney <paulmck@xxxxxxxxxxxxxxxxxx>
Reported-by: <rockorequin@xxxxxxxxxxx>
Signed-off-by: Li Zhong <zhong@xxxxxxxxxxxxxxxxxx>
---
drivers/scsi/scsi.c | 2 +-
drivers/scsi/scsi_error.c | 2 +-
include/scsi/scsi_cmnd.h | 2 ++
3 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 07322ec..24e7583 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -827,7 +827,7 @@ void scsi_finish_command(struct scsi_cmnd *cmd)
if (cmd->request->cmd_type != REQ_TYPE_BLOCK_PC) {
int old_good_bytes = good_bytes;
drv = scsi_cmd_to_driver(cmd);
- if (drv->done)
+ if (drv && drv->done)
good_bytes = drv->done(cmd);
/*
* USB may not give sense identifying bad sector and
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 2cfcbff..386f0c5 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -835,7 +835,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,

scsi_eh_restore_cmnd(scmd, &ses);

- if (sdrv->eh_action)
+ if (sdrv && sdrv->eh_action)
rtn = sdrv->eh_action(scmd, cmnd, cmnd_size, rtn);

return rtn;
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index 377df4a..063175d 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -134,6 +134,8 @@ struct scsi_cmnd {

static inline struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd)
{
+ if (!(cmd->request->rq_disk))
+ return NULL;
return *(struct scsi_driver **)cmd->request->rq_disk->private_data;
}

--
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/