aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorbrking@us.ibm.com <brking@us.ibm.com>2005-05-24 10:49:59 -0400
committerJames Bottomley <jejb@mulgrave.(none)>2005-06-03 13:25:35 -0400
commit521314c122ea0cd58e5184443b8cc28f82ee2136 (patch)
tree257d5792baa0f957b4fe1f71607a6882a5032dc9 /drivers/scsi
parentb1abb4d67f2a706f52a95064001e0c55d9be2d26 (diff)
[SCSI] sg: Command completion after remove oops
A problem exists todayin the sg driver that if an SG_IO request is outstanding to a device when it is removed from the system. The system may oops if that command completes later in time. 1. sg_remove gets called 2. sg_remove calls sg_finish_req_req on all pending requests This removes the Sg_request's from the headrp list in the Sg_fd 3. The sleeping SG_IO ioctl is woken. It does nothing and returns. 4. The caller closes the fd, which invokes sg_release 5. sg_release calls sg_remove_sfp. It finds no outstanding commands since the headrp list is empty, so it calls __sg_remove_sfp, which frees the sfp. 6. Now when sg_cmd_done gets called, sg uses upper_private_data in the Scsi_Request, which should point to the srp, which has been freed, so it points to freed memory. 7. sg then dereferences the srp pointer to get the sfp, and we oops. The fix is to NULL out the upper_private_data field in this path, which sg_cmd_done already checks for, which will prevent the oops from occurring. cpu 0x1: Vector: 300 (Data Access) at [c00000000fff7aa0] pc: d0000000002bbea8: .sg_cmd_done+0x70/0x394 [sg] lr: d000000000073304: .scsi_finish_command+0x10c/0x130 [scsi_mod] sp: c00000000fff7d20 msr: 8000000000009032 dar: 2f70726f63202f78 dsisr: 40000000 current = 0xc0000000024589b0 paca = 0xc0000000003da800 pid = 7, comm = events/1 [c00000000fff7dc0] d000000000073304 .scsi_finish_command+0x10c/0x130 [scsi_mod] [c00000000fff7e50] d00000000007317c .scsi_softirq+0x140/0x168 [scsi_mod] [c00000000fff7ef0] c0000000000634dc .__do_softirq+0xa0/0x17c [c00000000fff7f90] c000000000018430 .call_do_softirq+0x14/0x24 [c00000000ed472e0] c0000000000142e0 .do_softirq+0x74/0x9c [c00000000ed47370] c000000000013c9c .do_IRQ+0xe8/0x100 [c00000000ed473f0] c00000000000ae34 HardwareInterrupt_entry+0x8/0x54 c00000000003df28 .smp_call_function+0 x100/0x1d0 [c00000000ed47780] c0000000000ba99c .invalidate_bh_lrus+0x30/0x70 [c00000000ed47810] c0000000000b91a0 .invalidate_bdev+0x18/0x3c [c00000000ed478a0] c0000000000da7b8 .__invalidate_device+0x70/0x94 [c00000000ed47930] c0000000001d40bc .invalidate_partition+0x4c/0x7c [c00000000ed479c0] c00000000010a944 .del_gendisk+0x48/0x15c [c00000000ed47a50] d00000000003d55c .sd_remove+0x34/0xe4 [sd_mod] [c00000000ed47ae0] c0000000001c5d30 .device_release_driver+0x90/0xb4 [c00000000ed47b70] c0000000001c6130 .bus_remove_device+0xb0/0x12c [c00000000ed47c00] c0000000001c4378 .device_del+0x120/0x198 [c00000000ed47ca0] d00000000007dcdc .scsi_remove_device+0xb4/0x194 [scsi_mod] [c00000000ed47d30] d0000000000a5864 .ipr_worker_thread+0x1d4/0x27c [ipr] [c00000000ed47dd0] c0000000000734c4 .worker_thread+0x238/0x2f4 [c00000000ed47ee0] c0000000000796c0 .kthread+0xcc/0x11c [c00000000ed47f90] c000000000018ad0 .kernel_thread+0x4c/0x6c Signed-off-by: Brian King <brking@us.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/sg.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 7936aafc3d05..3d1d7bff38ed 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -2472,6 +2472,8 @@ sg_remove_request(Sg_fd * sfp, Sg_request * srp)
2472 if ((!sfp) || (!srp) || (!sfp->headrp)) 2472 if ((!sfp) || (!srp) || (!sfp->headrp))
2473 return res; 2473 return res;
2474 write_lock_irqsave(&sfp->rq_list_lock, iflags); 2474 write_lock_irqsave(&sfp->rq_list_lock, iflags);
2475 if (srp->my_cmdp)
2476 srp->my_cmdp->upper_private_data = NULL;
2475 prev_rp = sfp->headrp; 2477 prev_rp = sfp->headrp;
2476 if (srp == prev_rp) { 2478 if (srp == prev_rp) {
2477 sfp->headrp = prev_rp->nextrp; 2479 sfp->headrp = prev_rp->nextrp;